Cholla 3.0.1-dev
Cholla - Massively parallel hydro on GPUs
Loading...
Searching...
No Matches
ParameterMap.h
1#ifndef PARAMETERMAP_H
2#define PARAMETERMAP_H
3
4#include <climits>
5#include <cstdint>
6#include <cstdio>
7#include <map>
8#include <optional>
9#include <set>
10#include <string>
11#include <type_traits>
12
13#include "../utils/error_handling.h"
14
15// stuff inside this namespace is only meant to be used to implement ParameterMap
16namespace param_details
17{
18
19/* Kinds of errors from converting parameters to a type */
20enum class TypeErr { none, generic, boolean, out_of_range };
21
22/* function used to actually format/report the error message specified by the TypeErr enum */
23[[noreturn]] void Report_TypeErr_(const std::string& param, const std::string& str, const std::string& dtype,
24 TypeErr type_convert_err);
25
26/* @{
27 * helper functions that try to interpret a string as a given type.
28 *
29 * This returns the associated value if it has the specified type. If ``type_mismatch_is_err`` is
30 * true, then the program aborts with an error if the string is the wrong type. When
31 * ``type_mismatch_is_err``, this simply returns an empty result.
32 */
33param_details::TypeErr try_int64_(const std::string& str, std::int64_t& val);
34param_details::TypeErr try_double_(const std::string& str, double& val);
35param_details::TypeErr try_bool_(const std::string& str, bool& val);
36param_details::TypeErr try_string_(const std::string& str, std::string& val);
37
38// special case to make people's lives easier
39inline param_details::TypeErr try_int_(const std::string& str, int& val)
40{
41 std::int64_t tmp;
42 TypeErr err = try_int64_(str, tmp);
43 if ((err == param_details::TypeErr::none) and (INT_MIN <= tmp) && (tmp <= INT_MAX)) {
44 val = int(tmp);
45 return TypeErr::none;
46 }
47 return (err == TypeErr::none) ? TypeErr::out_of_range : err;
48}
49/* @} */
50} // namespace param_details
51
74{
75 public:
76 struct ParamEntry {
77 std::string param_str;
78 bool accessed;
79 };
80
81 private: // attributes
82 std::map<std::string, ParamEntry> entries_;
83
84 public: // interface methods
85 /* Reads parameters from a parameter file and arguments.
86 *
87 * \note
88 * We pass in a ``std::FILE`` object rather than a filename-string because that makes testing
89 * easier.
90 */
91 ParameterMap(std::FILE* fp, int argc, char** argv, bool close_fp = false);
92
93 /* An overload for the constructor */
94 ParameterMap(const std::string& fname, int argc, char** argv);
95
96 /* queries the number of parameters (mostly for testing purposes) */
97 std::size_t size() { return entries_.size(); }
98
99 /* queries whether the parameter exists. */
100 bool has_param(const std::string& param) { return entries_.find(param) != entries_.end(); }
101
102 /* queries whether the parameter exists and if it has the specified type.
103 *
104 * \note
105 * The result is always the same as ``has_param``, when ``T`` is ``std::string``.
106 */
107 template <typename T>
108 bool param_has_type(const std::string& param)
109 {
110 return try_get_<T>(param, true).has_value();
111 }
112
113 /* Retrieves the value associated with the specified parameter. If the
114 * parameter does not exist or does not have the specified type, then the
115 * program aborts with an error.
116 *
117 * \tparam The expected type of the parameter-value
118 *
119 * \note The name follows conventions of std::optional
120 */
121 template <typename T>
122 T value(const std::string& param)
123 {
124 std::optional<T> result = try_get_<T>(param, false);
125 if (not result.has_value()) {
126 CHOLLA_ERROR("The \"%s\" parameter was not specified.", param.c_str());
127 }
128 return result.value();
129 }
130
131 /* @{
132 * If the specified parameter exists, retrieve the associated value, otherwise return default_val.
133 * If the associated value does not have the specified type, the program aborts with an error.
134 *
135 * \param param The name of the parameter being queried.
136 * \param default_val The value to return in case the parameter was not defined.
137 *
138 * \note
139 * This is named after std::optional::value_or. It's my intention to replace this with a single
140 * template, but this is good enough for now!
141 *
142 * \note
143 * Except when considering strings, the return type is always the same as the default value
144 */
145 bool value_or(const std::string& param, bool default_val)
146 {
147 return try_get_<bool>(param, false).value_or(default_val);
148 }
149
150 int value_or(const std::string& param, int default_val) { return try_get_<int>(param, false).value_or(default_val); }
151
152 std::int64_t value_or(const std::string& param, std::int64_t default_val)
153 {
154 return try_get_<std::int64_t>(param, false).value_or(default_val);
155 }
156
157 double value_or(const std::string& param, double default_val)
158 {
159 return try_get_<double>(param, false).value_or(default_val);
160 }
161
162 std::string value_or(const std::string& param, const std::string& default_val)
163 {
164 return try_get_<std::string>(param, false).value_or(default_val);
165 }
166
167 std::string value_or(const std::string& param, const char* default_val)
168 {
169 return try_get_<std::string>(param, false).value_or(default_val);
170 }
171 /* @} */
172
173 /* Warns about parameters that have not been accessed with the ``value`` OR ``value_or`` methods.
174 *
175 * \param ignore_params a set of parameter names that should never be reported as unused
176 * \param abort_on_warning when true, the warning is reported as error that causes the program to
177 * abort. Default is false.
178 * \param suppress_warning_msg when true, the warning isn't actually printed (this only exists for
179 * testing purposes)
180 * \returns the number of unused parameters
181 */
182 int warn_unused_parameters(const std::set<std::string>& ignore_params, bool abort_on_warning = false,
183 bool suppress_warning_msg = false) const;
184
186 bool Contains_Table(std::string table_name) const;
187
193 void Enforce_Table_Content_Uniform_Access_Status(std::string table_name, bool expect_unused) const;
194
195 private: // private helper methods
196 /* helper function template that tries to retrieve values associated with a given parameter.
197 *
198 * This returns the associated value if it exists and has the specified type. The returned
199 * value is empty if the parameter doesn't exist. If the It can also be empty when type_abort is
200 * ``true`` and the specified type doesn't match the parameter (and is a type a parameter can
201 * have).
202 */
203 template <typename T>
204 std::optional<T> try_get_(const std::string& param, bool is_type_check);
205};
206
207template <typename T>
208std::optional<T> ParameterMap::try_get_(const std::string& param, bool is_type_check)
209{
210 auto keyvalue_pair = entries_.find(param);
211 if (keyvalue_pair == entries_.end()) return {}; // return emtpy option
212
213 const std::string& str = (keyvalue_pair->second).param_str; // string associate with param
214
215 // convert the string to the specified type and store it in out
216 T val{}; // default constructed
217 param_details::TypeErr err{}; // reports errors
218 const char* dtype_name; // used for formatting errors (we use a const char* rather than a
219 // std::string so we can hold string-literals)
220
221 // The branch of the following if-statement is picked at compile-time
222 if constexpr (std::is_same_v<T, bool>) {
223 err = param_details::try_bool_(str, val);
224 dtype_name = "bool";
225 } else if constexpr (std::is_same_v<T, std::int64_t>) {
226 err = param_details::try_int64_(str, val);
227 dtype_name = "int64_t";
228 } else if constexpr (std::is_same_v<T, double>) {
229 err = param_details::try_double_(str, val);
230 dtype_name = "double";
231 } else if constexpr (std::is_same_v<T, std::string>) {
232 err = param_details::try_string_(str, val);
233 dtype_name = "string";
234 } else if constexpr (std::is_same_v<T, int>) {
235 err = param_details::try_int_(str, val);
236 dtype_name = "int";
237 } else {
238 static_assert(always_false<T>, "template type can only be bool, int, std::int64_t, double, or std::string.");
239 }
240
241 // now do err-handling/value return
242 if (err != param_details::TypeErr::none) {
243 if (is_type_check) return {}; // return empty option
244 param_details::Report_TypeErr_(param, str, dtype_name, err);
245 }
246
247 if (not is_type_check) (keyvalue_pair->second).accessed = true; // record parameter-access
248 return {val};
249}
250
251#endif /* PARAMETERMAP_H */
A class that provides map-like access to parameter files.
Definition ParameterMap.h:74
Definition ParameterMap.h:76