Update clang-tidy to clang version 8
[alexxy/gromacs.git] / src / gromacs / utility / keyvaluetree.h
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 /*! \libinternal \file
36  * \brief
37  * Declares a data structure for JSON-like structured key-value mapping.
38  *
39  * A tree is composed of nodes that can have different types:
40  *  - _Value_ (gmx::KeyValueTreeValue) is a generic node that can
41  *    represent either a scalar value of arbitrary type, or an object or
42  *    an array.
43  *  - _Array_ (gmx::KeyValueTreeArray) is a collection of any number of values
44  *    (including zero).  The values can be of any type and different types
45  *    can be mixed in the same array.
46  *  - _Object_ (gmx::KeyValueTreeObject) is a collection of properties.
47  *    Each property must have a unique key.  Order of properties is preserved,
48  *    i.e., they can be iterated in the order they were added.
49  *  - _Property_ (gmx::KeyValueTreeProperty) is an arbitrary type of value
50  *    associated with a string key.
51  * The root object of a tree is typically an object, but could also be an
52  * array.  The data structure itself does not enforce any other constraints,
53  * but the context in which it is used can limit the allowed scalar types or,
54  * e.g., require arrays to have values of uniform type.  Also, several
55  * operations defined for the structure (string output, comparison,
56  * serialization, etc.) only work on a limited set of scalar types, or have
57  * limitations with the types of trees they work on (in particular, arrays are
58  * currently poorly supported).
59  *
60  * \author Teemu Murtola <teemu.murtola@gmail.com>
61  * \inlibraryapi
62  * \ingroup module_utility
63  */
64 #ifndef GMX_UTILITY_KEYVALUETREE_H
65 #define GMX_UTILITY_KEYVALUETREE_H
66
67 #include <algorithm>
68 #include <functional>
69 #include <map>
70 #include <string>
71 #include <utility>
72 #include <vector>
73
74 #include "gromacs/utility/any.h"
75 #include "gromacs/utility/real.h"
76
77 namespace gmx
78 {
79
80 class KeyValueTreeArray;
81 class KeyValueTreeObject;
82 class TextWriter;
83
84 /*! \libinternal \brief
85  * Identifies an entry in a key-value tree.
86  *
87  * This class is mainly an internal utility within the key-value tree
88  * implementation, but it is exposed on the API level where string-based
89  * specification of a location in the tree is necessary.  Constructors are not
90  * explicit to allow passing a simple string in contexts where a
91  * KeyValueTreePath is expected.
92  *
93  * The string specifying a location should start with a `/`, followed by the
94  * names of the properties separated by `/`.  For example, `/a/b/c` specifies
95  * property `c` in an object that is the value of `b` in an object that is the
96  * value of `a` at the root of the tree.
97  * Currently, there is no support for specifying paths to values within arrays
98  * (since none of the places where this is used implement array handling,
99  * either).
100  *
101  * \inlibraryapi
102  * \ingroup module_utility
103  */
104 class KeyValueTreePath
105 {
106     public:
107         //! Creates an empty path (corresponds to the root object).
108         KeyValueTreePath() = default;
109         //! Creates a path from given string representation.
110         KeyValueTreePath(const char *path);
111         //! Creates a path from given string representation.
112         KeyValueTreePath(const std::string &path);
113
114         //! Adds another element to the path, making it a child of the old path.
115         void append(const std::string &key) { path_.push_back(key); }
116         //! Adds elements from another path to the path.
117         void append(const KeyValueTreePath &other)
118         {
119             auto elements = other.elements();
120             path_.insert(path_.end(), elements.begin(), elements.end());
121         }
122         //! Removes the last element in the path, making it the parent path.
123         void pop_back() { return path_.pop_back(); }
124         //! Removes and returns the last element in the path.
125         std::string pop_last()
126         {
127             std::string result = std::move(path_.back());
128             path_.pop_back();
129             return result;
130         }
131
132         //! Whether the path is empty (pointing to the root object).
133         bool empty() const { return path_.empty(); }
134         //! Returns the number of elements (=nesting level) in the path.
135         size_t size() const { return path_.size(); }
136         //! Returns the i'th path element.
137         const std::string &operator[](int i) const { return path_[i]; }
138         //! Returns all the path elements.
139         const std::vector<std::string> &elements() const { return path_; }
140
141         //! Formats the path as a string for display.
142         std::string toString() const;
143
144     private:
145         std::vector<std::string> path_;
146 };
147
148 //! \cond libapi
149
150 //! Combines two paths as with KeyValueTreePath::append().
151 inline KeyValueTreePath operator+(const KeyValueTreePath &a, const KeyValueTreePath &b)
152 {
153     KeyValueTreePath result(a);
154     result.append(b);
155     return result;
156 }
157
158 //! Combines an element to a path as with KeyValueTreePath::append().
159 inline KeyValueTreePath operator+(const KeyValueTreePath &a, const std::string &b)
160 {
161     KeyValueTreePath result(a);
162     result.append(b);
163     return result;
164 }
165 //! \endcond
166
167 class KeyValueTreeValue
168 {
169     public:
170         //! Returns whether the value is an array (KeyValueTreeArray).
171         bool isArray() const;
172         //! Returns whether the value is an object (KeyValueTreeObject).
173         bool isObject() const;
174         //! Returns whether the value is of a given type.
175         template <typename T>
176         bool isType() const { return value_.isType<T>(); }
177         //! Returns the type of the value.
178         std::type_index type() const { return value_.type(); }
179
180         KeyValueTreeArray &asArray();
181         KeyValueTreeObject       &asObject();
182         const KeyValueTreeArray  &asArray() const;
183         const KeyValueTreeObject &asObject() const;
184         template <typename T>
185         const T                  &cast() const { return value_.cast<T>(); }
186
187         //! Returns the raw Any value (always possible).
188         const Any            &asAny() const { return value_; }
189
190     private:
191         explicit KeyValueTreeValue(Any &&value) : value_(std::move(value)) {}
192
193         Any             value_;
194
195         friend class KeyValueTreeBuilder;
196         friend class KeyValueTreeObjectBuilder;
197         friend class KeyValueTreeValueBuilder;
198 };
199
200 class KeyValueTreeArray
201 {
202     public:
203         //! Whether all elements of the array are objects.
204         bool isObjectArray() const
205         {
206             return std::all_of(values_.begin(), values_.end(),
207                                std::mem_fn(&KeyValueTreeValue::isObject));
208         }
209
210         //! Returns the values in the array.
211         const std::vector<KeyValueTreeValue> &values() const { return values_; }
212
213     private:
214         std::vector<KeyValueTreeValue> values_;
215
216         friend class KeyValueTreeArrayBuilderBase;
217 };
218
219 class KeyValueTreeProperty
220 {
221     public:
222         const std::string &key() const { return value_->first; }
223         const KeyValueTreeValue &value() const { return value_->second; }
224
225     private:
226         typedef std::map<std::string, KeyValueTreeValue>::const_iterator
227             IteratorType;
228
229         explicit KeyValueTreeProperty(IteratorType value) : value_(value) {}
230
231         IteratorType value_;
232
233         friend class KeyValueTreeObject;
234         friend class KeyValueTreeObjectBuilder;
235 };
236
237 class KeyValueTreeObject
238 {
239     public:
240         KeyValueTreeObject() = default;
241         //! Creates a deep copy of an object.
242         KeyValueTreeObject(const KeyValueTreeObject &other)
243         {
244             for (const auto &value : other.values_)
245             {
246                 auto iter = valueMap_.insert(std::make_pair(value.key(), value.value())).first;
247                 values_.push_back(KeyValueTreeProperty(iter));
248             }
249         }
250         //! Assigns a deep copy of an object.
251         KeyValueTreeObject &operator=(const KeyValueTreeObject &other)
252         {
253             KeyValueTreeObject tmp(other);
254             std::swap(tmp.valueMap_, valueMap_);
255             std::swap(tmp.values_, values_);
256             return *this;
257         }
258         //! Default move constructor.
259         KeyValueTreeObject(KeyValueTreeObject &&)            = default;
260         //! Default move assignment.
261         KeyValueTreeObject &operator=(KeyValueTreeObject &&) = default;
262
263         /*! \brief
264          * Returns all properties in the object.
265          *
266          * The properties are in the order they were added to the object.
267          */
268         const std::vector<KeyValueTreeProperty> &properties() const { return values_; }
269
270         //! Whether a property with given key exists.
271         bool keyExists(const std::string &key) const
272         {
273             return valueMap_.find(key) != valueMap_.end();
274         }
275         //! Returns value for a given key.
276         const KeyValueTreeValue &operator[](const std::string &key) const
277         {
278             GMX_ASSERT(keyExists(key), "Accessing non-existent value");
279             return valueMap_.at(key);
280         }
281
282         /*! \brief
283          * Returns whether the given object shares any keys with `this`.
284          */
285         bool hasDistinctProperties(const KeyValueTreeObject &obj) const;
286
287     private:
288         //! Keeps the properties by key.
289         std::map<std::string, KeyValueTreeValue> valueMap_;
290         //! Keeps the insertion order of properties.
291         std::vector<KeyValueTreeProperty>        values_;
292
293         friend class KeyValueTreeObjectBuilder;
294 };
295
296 /********************************************************************
297  * Inline functions that could not be declared within the classes
298  */
299
300 inline bool KeyValueTreeValue::isArray() const
301 {
302     return value_.isType<KeyValueTreeArray>();
303 }
304 inline bool KeyValueTreeValue::isObject() const
305 {
306     return value_.isType<KeyValueTreeObject>();
307 }
308 inline const KeyValueTreeArray &KeyValueTreeValue::asArray() const
309 {
310     return value_.cast<KeyValueTreeArray>();
311 }
312 inline const KeyValueTreeObject &KeyValueTreeValue::asObject() const
313 {
314     return value_.cast<KeyValueTreeObject>();
315 }
316 inline KeyValueTreeArray &KeyValueTreeValue::asArray()
317 {
318     return value_.castRef<KeyValueTreeArray>();
319 }
320 inline KeyValueTreeObject &KeyValueTreeValue::asObject()
321 {
322     return value_.castRef<KeyValueTreeObject>();
323 }
324
325 //! \cond libapi
326 /*! \brief
327  * Writes a human-readable representation of the tree with given writer.
328  *
329  * The output format is designed to be readable by humans; if some
330  * particular machine-readable format is needed, that should be
331  * implemented outside the generic key-value tree code.
332  *
333  * \ingroup module_utility
334  */
335 void dumpKeyValueTree(TextWriter *writer, const KeyValueTreeObject &tree);
336
337 /*! \brief
338  * Compares two KeyValueTrees and prints any differences.
339  *
340  * \ingroup module_utility
341  */
342 void compareKeyValueTrees(TextWriter               *writer,
343                           const KeyValueTreeObject &tree1,
344                           const KeyValueTreeObject &tree2,
345                           real                      ftol,
346                           real                      abstol);
347
348 //! Helper function to format a simple KeyValueTreeValue.
349 static inline std::string
350 simpleValueToString(const KeyValueTreeValue &value)
351 {
352     return simpleValueToString(value.asAny());
353 }
354
355 //! \endcond
356
357 } // namespace gmx
358
359 #endif