Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / utility / any.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 gmx::Any.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \inlibraryapi
41  * \ingroup module_utility
42  */
43 #ifndef GMX_UTILITY_ANY_H
44 #define GMX_UTILITY_ANY_H
45
46 #include <memory>
47 #include <string>
48 #include <type_traits>
49 #include <typeindex>
50 #include <typeinfo>
51 #include <utility>
52
53 #include "gromacs/utility/gmxassert.h"
54
55 namespace gmx
56 {
57
58 /*! \libinternal \brief
59  * Represents a dynamically typed value of an arbitrary type.
60  *
61  * To create a any, either initialize it as empty, or with the create()
62  * method (or the equivalent constructor, if the type parameter can be deduced
63  * and is clear to the reader from the context).
64  *
65  * To query the type of the contents in the any, use isEmpty(), type(), and
66  * isType().
67  *
68  * To access the value, you need to know the type as a compile-time constant
69  * (e.g., through branching based on isType()), and then use cast() or
70  * tryCast().
71  *
72  * Methods in this class do not throw unless otherwise indicated.
73  *
74  * This provides essentially the same functionality as boost::any.
75  *
76  * \ingroup module_utility
77  */
78 class Any
79 {
80 public:
81     /*! \brief
82      * Creates a any that holds the given value.
83      *
84      * \throws std::bad_alloc if out of memory.
85      *
86      * This method allows explicitly specifying the template argument,
87      * contrary to the templated constructor.
88      */
89     template<typename T>
90     static Any create(const T& value)
91     {
92         return Any(value);
93     }
94     /*! \brief
95      * Creates a any that holds the given value.
96      *
97      * \throws std::bad_alloc if out of memory.
98      *
99      * In addition to allowing specifying the template argument, this
100      * method avoids copying when move-construction is possible.
101      */
102     template<typename T>
103     static Any create(T&& value)
104     {
105         return Any(std::forward<T>(value));
106     }
107
108     //! Creates an empty any value.
109     Any() {}
110     /*! \brief
111      * Creates a any that holds the given value.
112      *
113      * \throws std::bad_alloc if out of memory.
114      */
115     template<typename T, typename = std::enable_if_t<!std::is_same<T, Any>::value>>
116     explicit Any(T&& value) : content_(new Content<std::decay_t<T>>(std::forward<T>(value)))
117     {
118     }
119     /*! \brief
120      * Creates a deep copy of a any.
121      *
122      * \throws std::bad_alloc if out of memory.
123      */
124     Any(const Any& other) : content_(other.cloneContent()) {}
125     //! Move-constructs a any.
126     Any(Any&& other) noexcept : content_(std::move(other.content_)) {}
127     /*! \brief
128      * Assigns the any.
129      *
130      * \throws std::bad_alloc if out of memory.
131      */
132     Any& operator=(const Any& other)
133     {
134         content_ = other.cloneContent();
135         return *this;
136     }
137     //! Move-assigns the any.
138     Any& operator=(Any&& other) noexcept
139     {
140         content_ = std::move(other.content_);
141         return *this;
142     }
143
144     //! Whether any value is stored.
145     bool isEmpty() const { return content_ == nullptr; }
146     //! Returns the dynamic type of the value that is currently stored.
147     std::type_index type() const
148     {
149         const std::type_info& info = !isEmpty() ? content_->typeInfo() : typeid(void);
150         return std::type_index(info);
151     }
152     //! Returns whether the type stored matches the template parameter.
153     template<typename T>
154     bool isType() const
155     {
156         return !isEmpty() && content_->typeInfo() == typeid(T);
157     }
158
159     /*! \brief
160      * Tries to get the value as the given type.
161      *
162      * \tparam T  Type to get.
163      * \returns Pointer to the value, or nullptr if the type does not match
164      *     the stored value.
165      */
166     template<typename T>
167     const T* tryCast() const
168     {
169         return isType<T>() ? &static_cast<Content<T>*>(content_.get())->value_ : nullptr;
170     }
171     /*! \brief
172      * Gets the value when the type is known.
173      *
174      * \tparam T  Type to get (which must match what the any stores).
175      *
176      * Asserts if the any is empty or does not contain the requested type.
177      */
178     template<typename T>
179     const T& cast() const
180     {
181         const T* value = tryCast<T>();
182         GMX_RELEASE_ASSERT(value != nullptr, "Cast to incorrect type");
183         return *value;
184     }
185     /*! \brief
186      * Tries to get the value as the given type as a non-const pointer.
187      *
188      * \tparam T  Type to get.
189      * \returns Pointer to the value, or nullptr if the type does not match
190      *     the stored value.
191      *
192      * This method allows modifying the value in-place, which is useful
193      * with more complicated data structures.
194      */
195     template<typename T>
196     T* tryCastRef()
197     {
198         return isType<T>() ? &static_cast<Content<T>*>(content_.get())->value_ : nullptr;
199     }
200     /*! \brief
201      * Gets the value when the type is known as a modifiable reference.
202      *
203      * \tparam T  Type to get (which must match what the any stores).
204      *
205      * Asserts if the any is empty or does not contain the requested type.
206      */
207     template<typename T>
208     T& castRef()
209     {
210         T* value = tryCastRef<T>();
211         GMX_RELEASE_ASSERT(value != nullptr, "Cast to incorrect type");
212         return *value;
213     }
214
215 private:
216     class IContent
217     {
218     public:
219         virtual ~IContent() {}
220         virtual const std::type_info&     typeInfo() const = 0;
221         virtual std::unique_ptr<IContent> clone() const    = 0;
222     };
223
224     template<typename T>
225     class Content : public IContent
226     {
227     public:
228         explicit Content(const T& value) : value_(value) {}
229         explicit Content(T&& value) : value_(std::move(value)) {}
230
231         const std::type_info&     typeInfo() const override { return typeid(T); }
232         std::unique_ptr<IContent> clone() const override
233         {
234             return std::make_unique<Content>(value_);
235         }
236
237         T value_;
238     };
239
240     //! Creates a deep copy of the content.
241     std::unique_ptr<IContent> cloneContent() const
242     {
243         return content_ != nullptr ? content_->clone() : nullptr;
244     }
245
246     std::unique_ptr<IContent> content_;
247 };
248
249 //! \cond libapi
250 /*! \brief
251  * Converts a Any value to a string.
252  *
253  * As the name suggests, only some types of "simple" values (such as int) are
254  * supported.  Asserts for unsupported types.
255  *
256  * \ingroup module_utility
257  */
258 std::string simpleValueToString(const Any& value);
259 //! \endcond
260
261 } // namespace gmx
262
263 #endif