SYCL: Avoid using no_init read accessor in rocFFT
[alexxy/gromacs.git] / src / gromacs / utility / strconvert.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2016,2017,2018,2019,2020, 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 common utility functions for conversions to and from strings.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \author Mark Abraham <mark.j.abraham@gmail.com>
41  * \inlibraryapi
42  * \ingroup module_utility
43  */
44 #ifndef GMX_UTILITY_STRCONVERT_H
45 #define GMX_UTILITY_STRCONVERT_H
46
47 #include <algorithm>
48 #include <array>
49 #include <optional>
50 #include <string>
51
52 #include "gromacs/utility/basedefinitions.h"
53 #include "gromacs/utility/exceptions.h"
54 #include "gromacs/utility/stringutil.h"
55
56 namespace gmx
57 {
58
59 //! \cond libapi
60 //! \addtogroup module_utility
61 //! \{
62
63 /*! \brief
64  * Parses a boolean from a string.
65  *
66  * \throws  InvalidInputError if `str` is not recognized as a boolean value.
67  */
68 bool boolFromString(const char* str);
69 /*! \brief
70  * Parses an integer from a string.
71  *
72  * \throws  InvalidInputError if `str` is not a valid integer.
73  *
74  * Also checks for overflow.
75  */
76 int intFromString(const char* str);
77 /*! \brief
78  * Parses a 64-bit integer from a string.
79  *
80  * \throws  InvalidInputError if `str` is not a valid integer.
81  *
82  * Also checks for overflow.
83  */
84 int64_t int64FromString(const char* str);
85 /*! \brief
86  * Parses a float value from a string.
87  *
88  * \throws  InvalidInputError if `str` is not a valid number.
89  *
90  * Also checks for overflow.
91  */
92 float floatFromString(const char* str);
93 /*! \brief
94  * Parses a double value from a string.
95  *
96  * \throws  InvalidInputError if `str` is not a valid number.
97  *
98  * Also checks for overflow.
99  */
100 double doubleFromString(const char* str);
101
102 /*! \brief
103  * Parses a value from a string to a given type.
104  *
105  * \tparam T Type of value to parse.
106  *
107  * `T` can only be one of the types that is explicity supported.
108  * The main use for this function is to write `fromString<real>(value)`,
109  * but it can also be used for other types for consistency.
110  */
111 template<typename T>
112 static inline T fromString(const char* str);
113 //! \copydoc fromString(const char *)
114 template<typename T>
115 static inline T fromString(const std::string& str)
116 {
117     return fromString<T>(str.c_str());
118 }
119 /*! \copydoc fromString(const char *)
120  *
121  * Provided for situations where overload resolution cannot easily resolve the
122  * desired std::string parameter.
123  */
124 template<typename T>
125 static inline T fromStdString(const std::string& str)
126 {
127     return fromString<T>(str.c_str());
128 }
129
130 //! Implementation for boolean values.
131 template<>
132 inline bool fromString<bool>(const char* str)
133 {
134     return boolFromString(str);
135 }
136 //! Implementation for integer values.
137 template<>
138 inline int fromString<int>(const char* str)
139 {
140     return intFromString(str);
141 }
142 //! Implementation for 64-bit integer values.
143 template<>
144 inline int64_t fromString<int64_t>(const char* str)
145 {
146     return int64FromString(str);
147 }
148 //! Implementation for float values.
149 template<>
150 inline float fromString<float>(const char* str)
151 {
152     return floatFromString(str);
153 }
154 //! Implementation for double values.
155 template<>
156 inline double fromString<double>(const char* str)
157 {
158     return doubleFromString(str);
159 }
160
161 /*! \brief
162  * Converts a boolean to a "true"/"false" string.
163  *
164  * Does not throw.
165  */
166 static inline const char* boolToString(bool value)
167 {
168     return value ? "true" : "false";
169 }
170 /*! \brief
171  * Returns a string containing the value of \c t.
172  *
173  * \throws std::bad_alloc if out of memory.
174  */
175 static inline std::string intToString(int t)
176 {
177     return formatString("%d", t);
178 }
179 //! \copydoc intToString(int)
180 static inline std::string int64ToString(int64_t t)
181 {
182     return formatString("%" PRId64, t);
183 }
184 //! \copydoc intToString(int)
185 static inline std::string doubleToString(double t)
186 {
187     return formatString("%g", t);
188 }
189
190 /*! \name
191  * Overloads for converting a value of a given type to a string.
192  *
193  * \throws std::bad_alloc if out of memory.
194  * \{
195  */
196 static inline std::string toString(bool t)
197 {
198     return boolToString(t);
199 }
200 static inline std::string toString(int t)
201 {
202     return intToString(t);
203 }
204 static inline std::string toString(int64_t t)
205 {
206     return int64ToString(t);
207 }
208 static inline std::string toString(float t)
209 {
210     return doubleToString(t);
211 }
212 static inline std::string toString(double t)
213 {
214     return doubleToString(t);
215 }
216 static inline std::string toString(std::string t)
217 {
218     return t;
219 }
220 //! \}
221
222 //! \}
223 //! \endcond
224
225 /*! \brief Convert a string into an array of values.
226  *
227  * \tparam ValueType array element type to convert into
228  * \tparam NumExpectedValues number of values of the array
229  *
230  * \returns an array containing the converted string, optionally null if
231  *          the white-space stripped string is empty
232  *
233  * \throws InvalidInputError if splitting the string at whitespaces does not
234  *                           result in NumExpectedValues or zero substrings
235  *
236  * \throws InvalidInputError if conversion of any of the NumExpectedValues
237  *                           substrings of the splitted input string fails
238  *
239  * Converts a string into an array of type ValueType with exactly NumExpectedValues.
240  *
241  * No result is returned if the string is empty or contains only whitespace .
242  *
243  */
244 template<typename ValueType, int NumExpectedValues>
245 static inline std::optional<std::array<ValueType, NumExpectedValues>>
246 parsedArrayFromInputString(const std::string& str)
247 {
248     // return nullopt right away if the string is just whitespace or empty
249     {
250         const std::string& strippedString = stripString(str);
251         if (strippedString.empty())
252         {
253             return std::nullopt;
254         }
255     }
256
257     const std::vector<std::string>& valuesAsStrings = splitString(str);
258
259     // throw right away if we don't have the expected number of string entries
260     if (valuesAsStrings.size() != NumExpectedValues)
261     {
262         const std::string errorMessage =
263                 "Expected empty string or string with " + intToString(NumExpectedValues)
264                 + " elements to convert, but received " + intToString(valuesAsStrings.size())
265                 + " elements instead.";
266         GMX_THROW(InvalidInputError(errorMessage));
267     }
268
269     // will throw if any conversion from string to value fails
270     std::array<ValueType, NumExpectedValues> valuesAsArray;
271     std::transform(std::begin(valuesAsStrings),
272                    std::end(valuesAsStrings),
273                    std::begin(valuesAsArray),
274                    [](const std::string& split) { return fromString<ValueType>(split); });
275
276     return { valuesAsArray };
277 }
278
279 /*! \brief Returns the input string, throwing an excpetion if the demanded
280  *         conversion to an array will not succeed.
281  *
282  * \tparam ValueType array element type to convert into
283  * \tparam NumExpectedValues number of values of the array
284  *
285  * \param[in] toConvert the string to convert
286  * \param[in] errorContextMessage the message to add to the thrown exceptions if
287  *                                conversion of the string is bound to fail at
288  *                                some point
289  * \returns the input string
290  *
291  * \throws InvalidInputError if splitting the string at whitespaces does not
292  *                           result in NumExpectedValues or zero substrings
293  *
294  * \throws InvalidInputError if conversion of any of the NumExpectedValues
295  *                           substrings of the splitted input string fails
296  *
297  * A typical use of this function would be in .mdp string option parsing
298  * where information in the .mdp file is transformed into the data that is
299  * stored in the .tpr file.
300  */
301 template<typename ValueType, int NumExpectedValues>
302 static inline std::string stringIdentityTransformWithArrayCheck(const std::string& toConvert,
303                                                                 const std::string& errorContextMessage)
304 {
305     // Attempt the conversion to an array so that the string parsing routine
306     // will throw an InvalidInputError if the string is not fit for conversion.
307     try
308     {
309         // The converted array is discarded.
310         gmx_unused const auto& val = parsedArrayFromInputString<ValueType, NumExpectedValues>(toConvert);
311     }
312     catch (const InvalidInputError& e)
313     {
314         InvalidInputError toThrow(errorContextMessage + std::string(e.what()));
315         GMX_THROW(toThrow);
316     }
317
318     return toConvert;
319 }
320
321 } // namespace gmx
322
323 #endif