b40cd161824414bcc74cb24793d6e66abc5a81c3
[alexxy/gromacs.git] / src / gromacs / utility / keyvaluetreetransform.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2016,2017,2018, 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 /*! \libinternal \file
36  * \brief
37  * Declares utilities for transforming key-value trees.
38  *
39  * See \ref page_mdmodules for the main use case that these support.
40  *
41  * \author Teemu Murtola <teemu.murtola@gmail.com>
42  * \inlibraryapi
43  * \ingroup module_utility
44  */
45 #ifndef GMX_UTILITY_KEYVALUETREETRANSFORM_H
46 #define GMX_UTILITY_KEYVALUETREETRANSFORM_H
47
48 #include <functional>
49 #include <string>
50 #include <typeindex>
51 #include <vector>
52
53 #include "gromacs/utility/classhelpers.h"
54 #include "gromacs/utility/keyvaluetree.h"
55 #include "gromacs/utility/variant.h"
56
57 namespace gmx
58 {
59
60 class IKeyValueTreeErrorHandler;
61 class KeyValueTreeObjectBuilder;
62
63 enum class StringCompareType;
64
65 class KeyValueTreeTransformResult;
66 class KeyValueTreeTransformRuleBuilder;
67 class KeyValueTreeTransformRulesScoped;
68
69 namespace internal
70 {
71 class KeyValueTreeTransformerImpl;
72 }
73
74 /*! \libinternal \brief
75  * Interface to declare rules for transforming key-value trees.
76  *
77  * This interface is used to add transformation rules for key-value trees.
78  * A transformation is a set of rules that is used to map an input key-value
79  * tree to an output key-value tree, with possible conversion steps performed
80  * in the process.  Currently, each rule maps one item from the source tree to
81  * one item in the target tree (it is possible to expand a single value into an
82  * object with multiple properties).  See KeyValueTreeTransformRuleBuilder for
83  * the kinds of rules currently supported.
84  *
85  * The main use currently is in converting flat-format mdp files to a
86  * structured internal representation.
87  *
88  * \inlibraryapi
89  * \ingroup module_utility
90  */
91 class IKeyValueTreeTransformRules
92 {
93     public:
94         /*! \brief
95          * Creates a new rule.
96          *
97          * Properties of the new rule must be specified using the returned
98          * builder.
99          */
100         virtual KeyValueTreeTransformRuleBuilder addRule() = 0;
101         /*! \brief
102          * Creates a scoped set of rules, where all rules use a target sub-tree.
103          *
104          * \param[in] scope Prefix defining the scope in the target tree
105          *
106          * Any rules added to the returned scope will have `scope` prefixed to
107          * their target paths, i.e., it is not possible to produce elements
108          * outside the specified subtree.
109          */
110         virtual KeyValueTreeTransformRulesScoped
111         scopedTransform(const KeyValueTreePath &scope) = 0;
112
113     protected:
114         virtual ~IKeyValueTreeTransformRules();
115 };
116
117 /*! \libinternal \brief
118  * Helper object returned from IKeyValueTreeTransformRules::scopedTransform().
119  *
120  * \inlibraryapi
121  * \ingroup module_utility
122  */
123 class KeyValueTreeTransformRulesScoped
124 {
125     public:
126         //! Internal constructor for creating the scope.
127         KeyValueTreeTransformRulesScoped(
128             internal::KeyValueTreeTransformerImpl *impl,
129             const KeyValueTreePath                &prefix);
130         //! Supports returning the object from IKeyValueTreeTransformRules::scopedTransform().
131         KeyValueTreeTransformRulesScoped(KeyValueTreeTransformRulesScoped &&other) noexcept;
132         //! Supports returning the object from IKeyValueTreeTransformRules::scopedTransform().
133         KeyValueTreeTransformRulesScoped &operator=(KeyValueTreeTransformRulesScoped &&other) noexcept;
134         ~KeyValueTreeTransformRulesScoped();
135
136         //! Returns the interface for adding rules to this scope.
137         IKeyValueTreeTransformRules *rules();
138
139     private:
140         class Impl;
141
142         PrivateImplPointer<Impl> impl_;
143 };
144
145 /*! \libinternal \brief
146  * Provides methods to specify one transformation rule.
147  *
148  * \if internal
149  * The builder is implemented as a set of nested objects, each of which is
150  * provides methods for setting a particular property of the rule.  Setting a
151  * property returns another object that has relevant methods for the context.
152  * This provides some structure to the methods, and catches at least some types
153  * of incorrect rules already at compile time.
154  * Additionally, if you use an IDE with completion facilities, it can nicely
155  * guide you through which values you need to specify.
156  * All values are stored within the main builder object, and the rule is
157  * created at the end of the statement.
158  * \endif
159  *
160  * \inlibraryapi
161  * \ingroup module_utility
162  */
163 class KeyValueTreeTransformRuleBuilder
164 {
165     public:
166         /*! \internal \brief
167          * Base class used for implementing parameter provider objects.
168          */
169         class Base
170         {
171             protected:
172                 //! Creates a parameter provider object within given builder.
173                 explicit Base(KeyValueTreeTransformRuleBuilder *builder)
174                     : builder_(builder)
175                 {
176                 }
177
178                 //! The parent builder.
179                 KeyValueTreeTransformRuleBuilder *builder_;
180         };
181
182         /*! \libinternal \brief
183          * Properties that can be specified after from().to().
184          *
185          * \tparam FromType Type specified for from() to map from.
186          * \tparam ToType Type specified for to() to map to.
187          */
188         template <typename FromType, typename ToType>
189         class ToValue : public Base
190         {
191             public:
192                 //! Creates a parameter provider object within given builder.
193                 explicit ToValue(KeyValueTreeTransformRuleBuilder *builder)
194                     : Base(builder)
195                 {
196                 }
197
198                 /*! \brief
199                  * Specifies the transformation function to convert the value
200                  * from FromType to ToType.
201                  */
202                 void transformWith(std::function<ToType(const FromType &)> transform)
203                 {
204                     builder_->addTransformToVariant(
205                             [transform] (const Variant &value)
206                             {
207                                 return Variant::create<ToType>(transform(value.cast<FromType>()));
208                             });
209                 }
210         };
211
212         /*! \libinternal \brief
213          * Properties that can be specified after from().toObject().
214          *
215          * \tparam FromType Type specified for from() to map from.
216          */
217         template <typename FromType>
218         class ToObject : public Base
219         {
220             public:
221                 //! Creates a parameter provider object within given builder.
222                 explicit ToObject(KeyValueTreeTransformRuleBuilder *builder)
223                     : Base(builder)
224                 {
225                 }
226
227                 /*! \brief
228                  * Specifies the transformation function to build the output
229                  * object.
230                  *
231                  * The transform should build the output object with the
232                  * provided builder.
233                  */
234                 void transformWith(std::function<void(KeyValueTreeObjectBuilder *, const FromType &)> transform)
235                 {
236                     builder_->addTransformToObject(
237                             [transform] (KeyValueTreeObjectBuilder *builder, const Variant &value)
238                             {
239                                 transform(builder, value.cast<FromType>());
240                             });
241                 }
242         };
243
244         /*! \libinternal \brief
245          * Properties that can be specified after from().
246          *
247          * \tparam FromType Type specified for from() to map from.
248          */
249         template <typename FromType>
250         class AfterFrom : public Base
251         {
252             public:
253                 //! Creates a parameter provider object within given builder.
254                 explicit AfterFrom(KeyValueTreeTransformRuleBuilder *builder)
255                     : Base(builder)
256                 {
257                 }
258
259                 /*! \brief
260                  * Specifies a rule that maps to a value at given path.
261                  *
262                  * \tparam ToType  Type to map to.
263                  * \param[in] path Path to map to.
264                  *
265                  * It is an error if multiple rules map to the same path, or to
266                  * a parent path of the target of an existing rule.
267                  * Note that it is possible to have a to() rule map to a child
268                  * of a toObject() rule, provided that the path is not created
269                  * by the object rule.
270                  */
271                 template <typename ToType>
272                 ToValue<FromType, ToType> to(const KeyValueTreePath &path)
273                 {
274                     builder_->setToPath(path);
275                     return ToValue<FromType, ToType>(builder_);
276                 }
277
278                 /*! \brief
279                  * Specifies a rule that maps to an object (collection of named
280                  * values) at given path.
281                  *
282                  * \param[in] path Path to map to.
283                  *
284                  * It is an error if multiple rules map to the same path, or to
285                  * a parent path of the target of an existing rule.
286                  * However, it is allowed to have two toObject() rules map to
287                  * the same path, provided that the properties they produce are
288                  * distinct.
289                  */
290                 ToObject<FromType> toObject(const KeyValueTreePath &path)
291                 {
292                     builder_->setToPath(path);
293                     return ToObject<FromType>(builder_);
294                 }
295         };
296
297         //! Internal constructor for creating a builder.
298         KeyValueTreeTransformRuleBuilder(internal::KeyValueTreeTransformerImpl *impl,
299                                          const KeyValueTreePath                &prefix);
300         //! Supports returning the builder from IKeyValueTreeTransformRules::addRule().
301         KeyValueTreeTransformRuleBuilder(KeyValueTreeTransformRuleBuilder &&)            = default;
302         //! Supports returning the builder from IKeyValueTreeTransformRules::addRule().
303         KeyValueTreeTransformRuleBuilder &operator=(KeyValueTreeTransformRuleBuilder &&) = default;
304         ~KeyValueTreeTransformRuleBuilder();
305
306         /*! \brief
307          * Specifies a rule that maps a value at given path.
308          *
309          * \tparam FromType Type of value expected at `path`.
310          * \param[in] path Path to map in this rule.
311          *
312          * If the input tree has `path`, but it is not of type `FromType`,
313          * the transform will produce an error.
314          *
315          * It is an error to use the same path in two from() rules.  Similarly,
316          * it is an error to use a child path of a path used in a different
317          * from() rule.
318          */
319         template <typename FromType>
320         AfterFrom<FromType> from(const KeyValueTreePath &path)
321         {
322             setFromPath(path);
323             setExpectedType(typeid(FromType));
324             return AfterFrom<FromType>(this);
325         }
326         /*! \brief
327          * Specifies how strings are matched when matching rules against a path.
328          *
329          * For properties of the object at `path`, `keyMatchType` is used for
330          * string comparison.
331          *
332          * This rule must be specified first for a path, before any other
333          * from() rule specifies the path or a subpath.
334          * The rule only applies to immediate properties at the given path, not
335          * recursively.
336          * It is an error to specify the match type multiple times for a path.
337          */
338         void keyMatchType(const KeyValueTreePath &path, StringCompareType keyMatchType)
339         {
340             setFromPath(path);
341             setKeyMatchType(keyMatchType);
342         }
343
344     private:
345         void setFromPath(const KeyValueTreePath &path);
346         void setExpectedType(const std::type_index &type);
347         void setToPath(const KeyValueTreePath &path);
348         void setKeyMatchType(StringCompareType keyMatchType);
349         void addTransformToVariant(const std::function<Variant(const Variant &)> &transform);
350         void addTransformToObject(const std::function<void(KeyValueTreeObjectBuilder *, const Variant &)> &transform);
351
352         class Data;
353
354         internal::KeyValueTreeTransformerImpl *impl_;
355         std::unique_ptr<Data>                  data_;
356 };
357
358 class KeyValueTreeTransformer
359 {
360     public:
361         KeyValueTreeTransformer();
362         ~KeyValueTreeTransformer();
363
364         IKeyValueTreeTransformRules *rules();
365
366         std::vector<KeyValueTreePath> mappedPaths() const;
367
368         KeyValueTreeTransformResult
369         transform(const KeyValueTreeObject  &tree,
370                   IKeyValueTreeErrorHandler *errorHandler) const;
371
372     private:
373         PrivateImplPointer<internal::KeyValueTreeTransformerImpl> impl_;
374 };
375
376 class IKeyValueTreeBackMapping
377 {
378     public:
379         virtual ~IKeyValueTreeBackMapping();
380
381         virtual KeyValueTreePath
382         originalPath(const KeyValueTreePath &path) const = 0;
383 };
384
385 class KeyValueTreeTransformResult
386 {
387     public:
388         KeyValueTreeObject object() { return std::move(object_); }
389         const IKeyValueTreeBackMapping &backMapping() const { return *mapping_; }
390
391     private:
392         typedef std::unique_ptr<IKeyValueTreeBackMapping> MappingPointer;
393
394         KeyValueTreeTransformResult(KeyValueTreeObject &&object,
395                                     MappingPointer     &&mapping)
396             : object_(std::move(object)), mapping_(std::move(mapping))
397         {
398         }
399
400         KeyValueTreeObject  object_;
401         MappingPointer      mapping_;
402
403         friend class internal::KeyValueTreeTransformerImpl;
404 };
405
406 } // namespace gmx
407
408 #endif