Update instructions in containers.rst
[gromacs.git] / src / gromacs / utility / keyvaluetreetransform.h
blob9c2a2f5acd5bdefa5a29ad612c290f93d2c9727a
1 /*
2 * This file is part of the GROMACS molecular simulation package.
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.
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
36 * \brief
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>
42 * \inlibraryapi
43 * \ingroup module_utility
45 #ifndef GMX_UTILITY_KEYVALUETREETRANSFORM_H
46 #define GMX_UTILITY_KEYVALUETREETRANSFORM_H
48 #include <functional>
49 #include <string>
50 #include <typeindex>
51 #include <vector>
53 #include "gromacs/utility/any.h"
54 #include "gromacs/utility/classhelpers.h"
55 #include "gromacs/utility/keyvaluetree.h"
57 namespace gmx
60 class IKeyValueTreeErrorHandler;
61 class KeyValueTreeObjectBuilder;
63 enum class StringCompareType;
65 class KeyValueTreeTransformResult;
66 class KeyValueTreeTransformRuleBuilder;
67 class KeyValueTreeTransformRulesScoped;
69 namespace internal
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.
88 * \inlibraryapi
89 * \ingroup module_utility
91 class IKeyValueTreeTransformRules
93 public:
94 /*! \brief
95 * Creates a new rule.
97 * Properties of the new rule must be specified using the returned
98 * builder.
100 virtual KeyValueTreeTransformRuleBuilder addRule() = 0;
101 /*! \brief
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 scopedTransform(const KeyValueTreePath& scope) = 0;
112 protected:
113 virtual ~IKeyValueTreeTransformRules();
116 /*! \libinternal \brief
117 * Helper object returned from IKeyValueTreeTransformRules::scopedTransform().
119 * \inlibraryapi
120 * \ingroup module_utility
122 class KeyValueTreeTransformRulesScoped
124 public:
125 //! Internal constructor for creating the scope.
126 KeyValueTreeTransformRulesScoped(internal::KeyValueTreeTransformerImpl* impl,
127 const KeyValueTreePath& prefix);
128 //! Supports returning the object from IKeyValueTreeTransformRules::scopedTransform().
129 KeyValueTreeTransformRulesScoped(KeyValueTreeTransformRulesScoped&& other) noexcept;
130 //! Supports returning the object from IKeyValueTreeTransformRules::scopedTransform().
131 KeyValueTreeTransformRulesScoped& operator=(KeyValueTreeTransformRulesScoped&& other) noexcept;
132 ~KeyValueTreeTransformRulesScoped();
134 //! Returns the interface for adding rules to this scope.
135 IKeyValueTreeTransformRules* rules();
137 private:
138 class Impl;
140 PrivateImplPointer<Impl> impl_;
143 /*! \libinternal \brief
144 * Provides methods to specify one transformation rule.
146 * \if internal
147 * The builder is implemented as a set of nested objects, each of which is
148 * provides methods for setting a particular property of the rule. Setting a
149 * property returns another object that has relevant methods for the context.
150 * This provides some structure to the methods, and catches at least some types
151 * of incorrect rules already at compile time.
152 * Additionally, if you use an IDE with completion facilities, it can nicely
153 * guide you through which values you need to specify.
154 * All values are stored within the main builder object, and the rule is
155 * created at the end of the statement.
156 * \endif
158 * \inlibraryapi
159 * \ingroup module_utility
161 class KeyValueTreeTransformRuleBuilder
163 public:
164 /*! \internal \brief
165 * Base class used for implementing parameter provider objects.
167 class Base
169 protected:
170 //! Creates a parameter provider object within given builder.
171 explicit Base(KeyValueTreeTransformRuleBuilder* builder) : builder_(builder) {}
173 //! The parent builder.
174 KeyValueTreeTransformRuleBuilder* builder_;
177 /*! \libinternal \brief
178 * Properties that can be specified after from().to().
180 * \tparam FromType Type specified for from() to map from.
181 * \tparam ToType Type specified for to() to map to.
183 template<typename FromType, typename ToType>
184 class ToValue : public Base
186 public:
187 //! Creates a parameter provider object within given builder.
188 explicit ToValue(KeyValueTreeTransformRuleBuilder* builder) : Base(builder) {}
190 /*! \brief
191 * Specifies the transformation function to convert the value
192 * from FromType to ToType.
194 void transformWith(std::function<ToType(const FromType&)> transform)
196 builder_->addTransformToAny([transform](const Any& value) {
197 return Any::create<ToType>(transform(value.cast<FromType>()));
202 /*! \libinternal \brief
203 * Properties that can be specified after from().toObject().
205 * \tparam FromType Type specified for from() to map from.
207 template<typename FromType>
208 class ToObject : public Base
210 public:
211 //! Creates a parameter provider object within given builder.
212 explicit ToObject(KeyValueTreeTransformRuleBuilder* builder) : Base(builder) {}
214 /*! \brief
215 * Specifies the transformation function to build the output
216 * object.
218 * The transform should build the output object with the
219 * provided builder.
221 void transformWith(std::function<void(KeyValueTreeObjectBuilder*, const FromType&)> transform)
223 builder_->addTransformToObject([transform](KeyValueTreeObjectBuilder* builder, const Any& value) {
224 transform(builder, value.cast<FromType>());
229 /*! \libinternal \brief
230 * Properties that can be specified after from().
232 * \tparam FromType Type specified for from() to map from.
234 template<typename FromType>
235 class AfterFrom : public Base
237 public:
238 //! Creates a parameter provider object within given builder.
239 explicit AfterFrom(KeyValueTreeTransformRuleBuilder* builder) : Base(builder) {}
241 /*! \brief
242 * Specifies a rule that maps to a value at given path.
244 * \tparam ToType Type to map to.
245 * \param[in] path Path to map to.
247 * It is an error if multiple rules map to the same path, or to
248 * a parent path of the target of an existing rule.
249 * Note that it is possible to have a to() rule map to a child
250 * of a toObject() rule, provided that the path is not created
251 * by the object rule.
253 template<typename ToType>
254 ToValue<FromType, ToType> to(const KeyValueTreePath& path)
256 builder_->setToPath(path);
257 return ToValue<FromType, ToType>(builder_);
260 /*! \brief
261 * Specifies a rule that maps to an object (collection of named
262 * values) at given path.
264 * \param[in] path Path to map to.
266 * It is an error if multiple rules map to the same path, or to
267 * a parent path of the target of an existing rule.
268 * However, it is allowed to have two toObject() rules map to
269 * the same path, provided that the properties they produce are
270 * distinct.
272 ToObject<FromType> toObject(const KeyValueTreePath& path)
274 builder_->setToPath(path);
275 return ToObject<FromType>(builder_);
279 //! Internal constructor for creating a builder.
280 KeyValueTreeTransformRuleBuilder(internal::KeyValueTreeTransformerImpl* impl,
281 const KeyValueTreePath& prefix);
282 //! Supports returning the builder from IKeyValueTreeTransformRules::addRule().
283 KeyValueTreeTransformRuleBuilder(KeyValueTreeTransformRuleBuilder&&) = default;
284 //! Supports returning the builder from IKeyValueTreeTransformRules::addRule().
285 KeyValueTreeTransformRuleBuilder& operator=(KeyValueTreeTransformRuleBuilder&&) = default;
286 ~KeyValueTreeTransformRuleBuilder(); // NOLINT(bugprone-exception-escape)
288 /*! \brief
289 * Specifies a rule that maps a value at given path.
291 * \tparam FromType Type of value expected at `path`.
292 * \param[in] path Path to map in this rule.
294 * If the input tree has `path`, but it is not of type `FromType`,
295 * the transform will produce an error.
297 * It is an error to use the same path in two from() rules. Similarly,
298 * it is an error to use a child path of a path used in a different
299 * from() rule.
301 template<typename FromType>
302 AfterFrom<FromType> from(const KeyValueTreePath& path)
304 setFromPath(path);
305 setExpectedType(typeid(FromType));
306 return AfterFrom<FromType>(this);
308 /*! \brief
309 * Specifies how strings are matched when matching rules against a path.
311 * For properties of the object at `path`, `keyMatchType` is used for
312 * string comparison.
314 * This rule must be specified first for a path, before any other
315 * from() rule specifies the path or a subpath.
316 * The rule only applies to immediate properties at the given path, not
317 * recursively.
318 * It is an error to specify the match type multiple times for a path.
320 void keyMatchType(const KeyValueTreePath& path, StringCompareType keyMatchType)
322 setFromPath(path);
323 setKeyMatchType(keyMatchType);
326 private:
327 void setFromPath(const KeyValueTreePath& path);
328 void setExpectedType(const std::type_index& type);
329 void setToPath(const KeyValueTreePath& path);
330 void setKeyMatchType(StringCompareType keyMatchType);
331 void addTransformToAny(const std::function<Any(const Any&)>& transform);
332 void addTransformToObject(const std::function<void(KeyValueTreeObjectBuilder*, const Any&)>& transform);
334 class Data;
336 internal::KeyValueTreeTransformerImpl* impl_;
337 std::unique_ptr<Data> data_;
340 class KeyValueTreeTransformer
342 public:
343 KeyValueTreeTransformer();
344 ~KeyValueTreeTransformer();
346 IKeyValueTreeTransformRules* rules();
348 std::vector<KeyValueTreePath> mappedPaths() const;
350 KeyValueTreeTransformResult transform(const KeyValueTreeObject& tree,
351 IKeyValueTreeErrorHandler* errorHandler) const;
353 private:
354 PrivateImplPointer<internal::KeyValueTreeTransformerImpl> impl_;
357 class IKeyValueTreeBackMapping
359 public:
360 virtual ~IKeyValueTreeBackMapping();
362 virtual KeyValueTreePath originalPath(const KeyValueTreePath& path) const = 0;
365 class KeyValueTreeTransformResult
367 public:
368 KeyValueTreeObject object() { return std::move(object_); }
369 const IKeyValueTreeBackMapping& backMapping() const { return *mapping_; }
371 private:
372 typedef std::unique_ptr<IKeyValueTreeBackMapping> MappingPointer;
374 KeyValueTreeTransformResult(KeyValueTreeObject&& object, MappingPointer&& mapping) :
375 object_(std::move(object)),
376 mapping_(std::move(mapping))
380 KeyValueTreeObject object_;
381 MappingPointer mapping_;
383 friend class internal::KeyValueTreeTransformerImpl;
386 } // namespace gmx
388 #endif