2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2016,2017, 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 a data structure for JSON-like structured key-value mapping.
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
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).
60 * \author Teemu Murtola <teemu.murtola@gmail.com>
62 * \ingroup module_utility
64 #ifndef GMX_UTILITY_KEYVALUETREE_H
65 #define GMX_UTILITY_KEYVALUETREE_H
74 #include "gromacs/utility/real.h"
75 #include "gromacs/utility/variant.h"
80 class KeyValueTreeArray
;
81 class KeyValueTreeObject
;
84 /*! \libinternal \brief
85 * Identifies an entry in a key-value tree.
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.
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,
102 * \ingroup module_utility
104 class KeyValueTreePath
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
);
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 //! Removes the last element in the path, making it the parent path.
117 void pop_back() { return path_
.pop_back(); }
118 //! Removes and returns the last element in the path.
119 std::string
pop_last()
121 std::string result
= std::move(path_
.back());
126 //! Whether the path is empty (pointing to the root object).
127 bool empty() const { return path_
.empty(); }
128 //! Returns the number of elements (=nesting level) in the path.
129 size_t size() const { return path_
.size(); }
130 //! Returns the i'th path element.
131 const std::string
&operator[](int i
) const { return path_
[i
]; }
132 //! Returns all the path elements.
133 const std::vector
<std::string
> &elements() const { return path_
; }
135 //! Formats the path as a string for display.
136 std::string
toString() const;
139 std::vector
<std::string
> path_
;
142 class KeyValueTreeValue
145 //! Returns whether the value is an array (KeyValueTreeArray).
146 bool isArray() const;
147 //! Returns whether the value is an object (KeyValueTreeObject).
148 bool isObject() const;
149 //! Returns whether the value is of a given type.
150 template <typename T
>
151 bool isType() const { return value_
.isType
<T
>(); }
152 //! Returns the type of the value.
153 std::type_index
type() const { return value_
.type(); }
155 KeyValueTreeArray
&asArray();
156 KeyValueTreeObject
&asObject();
157 const KeyValueTreeArray
&asArray() const;
158 const KeyValueTreeObject
&asObject() const;
159 template <typename T
>
160 const T
&cast() const { return value_
.cast
<T
>(); }
162 //! Returns the raw Variant value (always possible).
163 const Variant
&asVariant() const { return value_
; }
166 explicit KeyValueTreeValue(Variant
&&value
) : value_(std::move(value
)) {}
170 friend class KeyValueTreeBuilder
;
171 friend class KeyValueTreeObjectBuilder
;
172 friend class KeyValueTreeValueBuilder
;
175 class KeyValueTreeArray
178 //! Whether all elements of the array are objects.
179 bool isObjectArray() const
181 return std::all_of(values_
.begin(), values_
.end(),
182 std::mem_fn(&KeyValueTreeValue::isObject
));
185 //! Returns the values in the array.
186 const std::vector
<KeyValueTreeValue
> &values() const { return values_
; }
189 std::vector
<KeyValueTreeValue
> values_
;
191 friend class KeyValueTreeArrayBuilderBase
;
194 class KeyValueTreeProperty
197 const std::string
&key() const { return value_
->first
; }
198 const KeyValueTreeValue
&value() const { return value_
->second
; }
201 typedef std::map
<std::string
, KeyValueTreeValue
>::const_iterator
204 explicit KeyValueTreeProperty(IteratorType value
) : value_(value
) {}
208 friend class KeyValueTreeObject
;
209 friend class KeyValueTreeObjectBuilder
;
212 class KeyValueTreeObject
215 KeyValueTreeObject() = default;
216 //! Creates a deep copy of an object.
217 KeyValueTreeObject(const KeyValueTreeObject
&other
)
219 for (const auto &value
: other
.values_
)
221 auto iter
= valueMap_
.insert(std::make_pair(value
.key(), value
.value())).first
;
222 values_
.push_back(KeyValueTreeProperty(iter
));
225 //! Assigns a deep copy of an object.
226 KeyValueTreeObject
&operator=(KeyValueTreeObject
&other
)
228 KeyValueTreeObject
tmp(other
);
229 std::swap(tmp
.valueMap_
, valueMap_
);
230 std::swap(tmp
.values_
, values_
);
233 //! Default move constructor.
234 KeyValueTreeObject(KeyValueTreeObject
&&) = default;
235 //! Default move assignment.
236 KeyValueTreeObject
&operator=(KeyValueTreeObject
&&) = default;
239 * Returns all properties in the object.
241 * The properties are in the order they were added to the object.
243 const std::vector
<KeyValueTreeProperty
> &properties() const { return values_
; }
245 //! Whether a property with given key exists.
246 bool keyExists(const std::string
&key
) const
248 return valueMap_
.find(key
) != valueMap_
.end();
250 //! Returns value for a given key.
251 const KeyValueTreeValue
&operator[](const std::string
&key
) const
253 GMX_ASSERT(keyExists(key
), "Accessing non-existent value");
254 return valueMap_
.at(key
);
258 * Returns whether the given object shares any keys with `this`.
260 bool hasDistinctProperties(const KeyValueTreeObject
&obj
) const;
263 * Writes a string representation of the object with given writer.
265 * The output format is designed to be readable by humans; if some
266 * particular machine-readable format is needed, that should be
267 * implemented outside the generic key-value tree code.
269 void writeUsing(TextWriter
*writer
) const;
272 //! Keeps the properties by key.
273 std::map
<std::string
, KeyValueTreeValue
> valueMap_
;
274 //! Keeps the insertion order of properties.
275 std::vector
<KeyValueTreeProperty
> values_
;
277 friend class KeyValueTreeObjectBuilder
;
280 /********************************************************************
281 * Inline functions that could not be declared within the classes
284 inline bool KeyValueTreeValue::isArray() const
286 return value_
.isType
<KeyValueTreeArray
>();
288 inline bool KeyValueTreeValue::isObject() const
290 return value_
.isType
<KeyValueTreeObject
>();
292 inline const KeyValueTreeArray
&KeyValueTreeValue::asArray() const
294 return value_
.cast
<KeyValueTreeArray
>();
296 inline const KeyValueTreeObject
&KeyValueTreeValue::asObject() const
298 return value_
.cast
<KeyValueTreeObject
>();
300 inline KeyValueTreeArray
&KeyValueTreeValue::asArray()
302 return value_
.castRef
<KeyValueTreeArray
>();
304 inline KeyValueTreeObject
&KeyValueTreeValue::asObject()
306 return value_
.castRef
<KeyValueTreeObject
>();
311 * Compares two KeyValueTrees and prints any differences.
313 * \ingroup module_utility
315 void compareKeyValueTrees(TextWriter
*writer
,
316 const KeyValueTreeObject
&tree1
,
317 const KeyValueTreeObject
&tree2
,