2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
35 /*! \libinternal \file
37 * Declares utilities for transforming key-value trees.
39 * See \ref page_mdmodules for the main use case that these support.
41 * \author Teemu Murtola <teemu.murtola@gmail.com>
43 * \ingroup module_utility
45 #ifndef GMX_UTILITY_KEYVALUETREETRANSFORM_H
46 #define GMX_UTILITY_KEYVALUETREETRANSFORM_H
53 #include "gromacs/utility/classhelpers.h"
54 #include "gromacs/utility/keyvaluetree.h"
55 #include "gromacs/utility/variant.h"
60 class IKeyValueTreeErrorHandler
;
61 class KeyValueTreeObjectBuilder
;
63 enum class StringCompareType
;
65 class KeyValueTreeTransformResult
;
66 class KeyValueTreeTransformRuleBuilder
;
67 class KeyValueTreeTransformRulesScoped
;
71 class KeyValueTreeTransformerImpl
;
74 /*! \libinternal \brief
75 * Interface to declare rules for transforming key-value trees.
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.
85 * The main use currently is in converting flat-format mdp files to a
86 * structured internal representation.
89 * \ingroup module_utility
91 class IKeyValueTreeTransformRules
97 * Properties of the new rule must be specified using the returned
100 virtual KeyValueTreeTransformRuleBuilder
addRule() = 0;
102 * Creates a scoped set of rules, where all rules use a target sub-tree.
104 * \param[in] scope Prefix defining the scope in the target tree
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.
110 virtual KeyValueTreeTransformRulesScoped
111 scopedTransform(const KeyValueTreePath
&scope
) = 0;
114 virtual ~IKeyValueTreeTransformRules();
117 /*! \libinternal \brief
118 * Helper object returned from IKeyValueTreeTransformRules::scopedTransform().
121 * \ingroup module_utility
123 class KeyValueTreeTransformRulesScoped
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();
136 //! Returns the interface for adding rules to this scope.
137 IKeyValueTreeTransformRules
*rules();
142 PrivateImplPointer
<Impl
> impl_
;
145 /*! \libinternal \brief
146 * Provides methods to specify one transformation rule.
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.
161 * \ingroup module_utility
163 class KeyValueTreeTransformRuleBuilder
167 * Base class used for implementing parameter provider objects.
172 //! Creates a parameter provider object within given builder.
173 explicit Base(KeyValueTreeTransformRuleBuilder
*builder
)
178 //! The parent builder.
179 KeyValueTreeTransformRuleBuilder
*builder_
;
182 /*! \libinternal \brief
183 * Properties that can be specified after from().to().
185 * \tparam FromType Type specified for from() to map from.
186 * \tparam ToType Type specified for to() to map to.
188 template <typename FromType
, typename ToType
>
189 class ToValue
: public Base
192 //! Creates a parameter provider object within given builder.
193 explicit ToValue(KeyValueTreeTransformRuleBuilder
*builder
)
199 * Specifies the transformation function to convert the value
200 * from FromType to ToType.
202 void transformWith(std::function
<ToType(const FromType
&)> transform
)
204 builder_
->addTransformToVariant(
205 [transform
] (const Variant
&value
)
207 return Variant::create
<ToType
>(transform(value
.cast
<FromType
>()));
212 /*! \libinternal \brief
213 * Properties that can be specified after from().toObject().
215 * \tparam FromType Type specified for from() to map from.
217 template <typename FromType
>
218 class ToObject
: public Base
221 //! Creates a parameter provider object within given builder.
222 explicit ToObject(KeyValueTreeTransformRuleBuilder
*builder
)
228 * Specifies the transformation function to build the output
231 * The transform should build the output object with the
234 void transformWith(std::function
<void(KeyValueTreeObjectBuilder
*, const FromType
&)> transform
)
236 builder_
->addTransformToObject(
237 [transform
] (KeyValueTreeObjectBuilder
*builder
, const Variant
&value
)
239 transform(builder
, value
.cast
<FromType
>());
244 /*! \libinternal \brief
245 * Properties that can be specified after from().
247 * \tparam FromType Type specified for from() to map from.
249 template <typename FromType
>
250 class AfterFrom
: public Base
253 //! Creates a parameter provider object within given builder.
254 explicit AfterFrom(KeyValueTreeTransformRuleBuilder
*builder
)
260 * Specifies a rule that maps to a value at given path.
262 * \tparam ToType Type to map to.
263 * \param[in] path Path to map to.
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.
271 template <typename ToType
>
272 ToValue
<FromType
, ToType
> to(const KeyValueTreePath
&path
)
274 builder_
->setToPath(path
);
275 return ToValue
<FromType
, ToType
>(builder_
);
279 * Specifies a rule that maps to an object (collection of named
280 * values) at given path.
282 * \param[in] path Path to map to.
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
290 ToObject
<FromType
> toObject(const KeyValueTreePath
&path
)
292 builder_
->setToPath(path
);
293 return ToObject
<FromType
>(builder_
);
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();
307 * Specifies a rule that maps a value at given path.
309 * \tparam FromType Type of value expected at `path`.
310 * \param[in] path Path to map in this rule.
312 * If the input tree has `path`, but it is not of type `FromType`,
313 * the transform will produce an error.
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
319 template <typename FromType
>
320 AfterFrom
<FromType
> from(const KeyValueTreePath
&path
)
323 setExpectedType(typeid(FromType
));
324 return AfterFrom
<FromType
>(this);
327 * Specifies how strings are matched when matching rules against a path.
329 * For properties of the object at `path`, `keyMatchType` is used for
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
336 * It is an error to specify the match type multiple times for a path.
338 void keyMatchType(const KeyValueTreePath
&path
, StringCompareType keyMatchType
)
341 setKeyMatchType(keyMatchType
);
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
);
354 internal::KeyValueTreeTransformerImpl
*impl_
;
355 std::unique_ptr
<Data
> data_
;
358 class KeyValueTreeTransformer
361 KeyValueTreeTransformer();
362 ~KeyValueTreeTransformer();
364 IKeyValueTreeTransformRules
*rules();
366 std::vector
<KeyValueTreePath
> mappedPaths() const;
368 KeyValueTreeTransformResult
369 transform(const KeyValueTreeObject
&tree
,
370 IKeyValueTreeErrorHandler
*errorHandler
) const;
373 PrivateImplPointer
<internal::KeyValueTreeTransformerImpl
> impl_
;
376 class IKeyValueTreeBackMapping
379 virtual ~IKeyValueTreeBackMapping();
381 virtual KeyValueTreePath
382 originalPath(const KeyValueTreePath
&path
) const = 0;
385 class KeyValueTreeTransformResult
388 KeyValueTreeObject
object() { return std::move(object_
); }
389 const IKeyValueTreeBackMapping
&backMapping() const { return *mapping_
; }
392 typedef std::unique_ptr
<IKeyValueTreeBackMapping
> MappingPointer
;
394 KeyValueTreeTransformResult(KeyValueTreeObject
&&object
,
395 MappingPointer
&&mapping
)
396 : object_(std::move(object
)), mapping_(std::move(mapping
))
400 KeyValueTreeObject object_
;
401 MappingPointer mapping_
;
403 friend class internal::KeyValueTreeTransformerImpl
;