Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Utility.hh
Go to the documentation of this file.
1//
2// MIT License
3// Copyright (c) 2020 Jonathan R. Madsen
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
12// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
13// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
16// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
17// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18//
19// Global utility functions
20//
21
22#pragma once
23
24#include <cctype>
25#include <cstdlib>
26#include <functional>
27#include <iomanip>
28#include <iostream>
29#include <map>
30#include <mutex>
31#include <set>
32#include <sstream> // IWYU pragma: keep
33#include <string>
34#include <tuple>
35#include <utility>
36
37namespace PTL
38{
39//--------------------------------------------------------------------------------------//
40// use this function to get rid of "unused parameter" warnings
41//
42template <typename... Args>
43void
45{}
46
47//--------------------------------------------------------------------------------------//
48// a non-string environment option with a string identifier
49template <typename Tp>
50using EnvChoice = std::tuple<Tp, std::string, std::string>;
51
52//--------------------------------------------------------------------------------------//
53// list of environment choices with non-string and string identifiers
54template <typename Tp>
55using EnvChoiceList = std::set<EnvChoice<Tp>>;
56
57//--------------------------------------------------------------------------------------//
58
60{
61public:
62 using mutex_t = std::mutex;
63 using string_t = std::string;
64 using env_map_t = std::multimap<string_t, string_t>;
65 using env_pair_t = std::pair<string_t, string_t>;
66
67public:
69 {
70 static EnvSettings* _instance = new EnvSettings();
71 return _instance;
72 }
73
74public:
75 template <typename Tp>
76 void insert(const std::string& env_id, Tp val)
77 {
78 std::stringstream ss;
79 ss << std::boolalpha << val;
80 m_mutex.lock();
81 if(m_env.find(env_id) != m_env.end())
82 {
83 for(const auto& itr : m_env)
84 if(itr.first == env_id && itr.second == ss.str())
85 {
86 m_mutex.unlock();
87 return;
88 }
89 }
90 m_env.insert(env_pair_t(env_id, ss.str()));
91 m_mutex.unlock();
92 }
93
94 template <typename Tp>
95 void insert(const std::string& env_id, EnvChoice<Tp> choice)
96 {
97 Tp& val = std::get<0>(choice);
98 std::string& str_val = std::get<1>(choice);
99 std::string& descript = std::get<2>(choice);
100
101 std::stringstream ss, ss_long;
102 ss << std::boolalpha << val;
103 ss_long << std::boolalpha << std::setw(8) << std::left << val << " # (\""
104 << str_val << "\") " << descript;
105 m_mutex.lock();
106 if(m_env.find(env_id) != m_env.end())
107 {
108 for(const auto& itr : m_env)
109 if(itr.first == env_id && itr.second == ss.str())
110 {
111 m_mutex.unlock();
112 return;
113 }
114 }
115 m_env.insert(env_pair_t(env_id, ss_long.str()));
116 m_mutex.unlock();
117 }
118
119 const env_map_t& get() const { return m_env; }
120 mutex_t& mutex() const { return m_mutex; }
121
122 friend std::ostream& operator<<(std::ostream& os, const EnvSettings& env)
123 {
124 std::stringstream filler;
125 filler.fill('#');
126 filler << std::setw(90) << "";
127 std::stringstream ss;
128 ss << filler.str() << "\n# Environment settings:\n";
129 env.mutex().lock();
130 for(const auto& itr : env.get())
131 {
132 ss << "# " << std::setw(35) << std::right << itr.first << "\t = \t"
133 << std::left << itr.second << "\n";
134 }
135 env.mutex().unlock();
136 ss << filler.str();
137 os << ss.str() << std::endl;
138 return os;
139 }
140
141private:
142 env_map_t m_env;
143 mutable mutex_t m_mutex;
144};
145
146//--------------------------------------------------------------------------------------//
147// use this function to get an environment variable setting +
148// a default if not defined, e.g.
149// int num_threads =
150// GetEnv<int>("FORCENUMBEROFTHREADS",
151// std::thread::hardware_concurrency());
152//
153template <typename Tp>
154Tp
155GetEnv(const std::string& env_id, Tp _default = Tp())
156{
157 char* env_var = std::getenv(env_id.c_str());
158 if(env_var)
159 {
160 std::string str_var = std::string(env_var);
161 std::istringstream iss(str_var);
162 Tp var = Tp();
163 iss >> var;
164 // record value defined by environment
165 EnvSettings::GetInstance()->insert<Tp>(env_id, var);
166 return var;
167 }
168 // record default value
169 EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
170
171 // return default if not specified in environment
172 return _default;
173}
174
175//--------------------------------------------------------------------------------------//
176// overload for boolean
177//
178template <>
179inline bool
180GetEnv(const std::string& env_id, bool _default)
181{
182 char* env_var = std::getenv(env_id.c_str());
183 if(env_var)
184 {
185 std::string var = std::string(env_var);
186 bool val = true;
187 if(var.find_first_not_of("0123456789") == std::string::npos)
188 val = (bool) atoi(var.c_str());
189 else
190 {
191 for(auto& itr : var)
192 itr = (char)std::tolower(itr);
193 if(var == "off" || var == "false")
194 val = false;
195 }
196 // record value defined by environment
197 EnvSettings::GetInstance()->insert<bool>(env_id, val);
198 return val;
199 }
200 // record default value
201 EnvSettings::GetInstance()->insert<bool>(env_id, false);
202
203 // return default if not specified in environment
204 return _default;
205}
206
207//--------------------------------------------------------------------------------------//
208// overload for GetEnv + message when set
209//
210template <typename Tp>
211Tp
212GetEnv(const std::string& env_id, Tp _default, const std::string& msg)
213{
214 char* env_var = std::getenv(env_id.c_str());
215 if(env_var)
216 {
217 std::string str_var = std::string(env_var);
218 std::istringstream iss(str_var);
219 Tp var = Tp();
220 iss >> var;
221 std::cout << "Environment variable \"" << env_id << "\" enabled with "
222 << "value == " << var << ". " << msg << std::endl;
223 // record value defined by environment
224 EnvSettings::GetInstance()->insert<Tp>(env_id, var);
225 return var;
226 }
227 // record default value
228 EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
229
230 // return default if not specified in environment
231 return _default;
232}
233
234//--------------------------------------------------------------------------------------//
235// use this function to get an environment variable setting from set of choices
236//
237// EnvChoiceList<int> choices =
238// { EnvChoice<int>(NN, "NN", "nearest neighbor interpolation"),
239// EnvChoice<int>(LINEAR, "LINEAR", "bilinear interpolation"),
240// EnvChoice<int>(CUBIC, "CUBIC", "bicubic interpolation") };
241//
242// int eInterp = GetEnv<int>("INTERPOLATION", choices, CUBIC);
243//
244template <typename Tp>
245Tp
246GetEnv(const std::string& env_id, const EnvChoiceList<Tp>& _choices, Tp _default)
247{
248 auto asupper = [](std::string var) {
249 for(auto& itr : var)
250 itr = (char)std::toupper(itr);
251 return var;
252 };
253
254 char* env_var = std::getenv(env_id.c_str());
255 if(env_var)
256 {
257 std::string str_var = std::string(env_var);
258 std::string upp_var = asupper(str_var);
259 Tp var = Tp();
260 // check to see if string matches a choice
261 for(const auto& itr : _choices)
262 {
263 if(asupper(std::get<1>(itr)) == upp_var)
264 {
265 // record value defined by environment
266 EnvSettings::GetInstance()->insert(env_id, itr);
267 return std::get<0>(itr);
268 }
269 }
270 std::istringstream iss(str_var);
271 iss >> var;
272 // check to see if string matches a choice
273 for(const auto& itr : _choices)
274 {
275 if(var == std::get<0>(itr))
276 {
277 // record value defined by environment
278 EnvSettings::GetInstance()->insert(env_id, itr);
279 return var;
280 }
281 }
282 // the value set in env did not match any choices
283 std::stringstream ss;
284 ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line "
285 << __LINE__ << ")! Invalid selection for \"" << env_id
286 << "\". Valid choices are:\n";
287 for(const auto& itr : _choices)
288 ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
289 << std::get<2>(itr) << ")\n";
290 std::cerr << ss.str() << std::endl;
291 abort();
292 }
293
294 std::string _name = "???";
295 std::string _desc = "description not provided";
296 for(const auto& itr : _choices)
297 if(std::get<0>(itr) == _default)
298 {
299 _name = std::get<1>(itr);
300 _desc = std::get<2>(itr);
301 break;
302 }
303
304 // record default value
305 EnvSettings::GetInstance()->insert(env_id, EnvChoice<Tp>(_default, _name, _desc));
306
307 // return default if not specified in environment
308 return _default;
309}
310
311//--------------------------------------------------------------------------------------//
312
313template <typename Tp>
314Tp
315GetChoice(const EnvChoiceList<Tp>& _choices, const std::string& str_var)
316{
317 auto asupper = [](std::string var) {
318 for(auto& itr : var)
319 itr = (char)std::toupper(itr);
320 return var;
321 };
322
323 std::string upp_var = asupper(str_var);
324 Tp var = Tp();
325 // check to see if string matches a choice
326 for(const auto& itr : _choices)
327 {
328 if(asupper(std::get<1>(itr)) == upp_var)
329 {
330 // record value defined by environment
331 return std::get<0>(itr);
332 }
333 }
334 std::istringstream iss(str_var);
335 iss >> var;
336 // check to see if string matches a choice
337 for(const auto& itr : _choices)
338 {
339 if(var == std::get<0>(itr))
340 {
341 // record value defined by environment
342 return var;
343 }
344 }
345 // the value set in env did not match any choices
346 std::stringstream ss;
347 ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line " << __LINE__
348 << ")! Invalid selection \"" << str_var << "\". Valid choices are:\n";
349 for(const auto& itr : _choices)
350 ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
351 << std::get<2>(itr) << ")\n";
352 std::cerr << ss.str() << std::endl;
353 abort();
354}
355
356//--------------------------------------------------------------------------------------//
357
358inline void
359PrintEnv(std::ostream& os = std::cout)
360{
361 os << (*EnvSettings::GetInstance());
362}
363
364//--------------------------------------------------------------------------------------//
365
367{
368 template <typename FuncT>
369 ScopeDestructor(FuncT&& _func)
370 : m_functor(std::forward<FuncT>(_func))
371 {}
372
373 // delete copy operations
376
377 // allow move operations
379 : m_functor(std::move(rhs.m_functor))
380 {
381 rhs.m_functor = []() {};
382 }
383
385 {
386 if(this != &rhs)
387 {
388 m_functor = std::move(rhs.m_functor);
389 rhs.m_functor = []() {};
390 }
391 return *this;
392 }
393
394 ~ScopeDestructor() { m_functor(); }
395
396private:
397 std::function<void()> m_functor = []() {};
398};
399
400//--------------------------------------------------------------------------------------//
401
402} // namespace PTL
std::pair< string_t, string_t > env_pair_t
Definition Utility.hh:65
mutex_t & mutex() const
Definition Utility.hh:120
void insert(const std::string &env_id, EnvChoice< Tp > choice)
Definition Utility.hh:95
void insert(const std::string &env_id, Tp val)
Definition Utility.hh:76
std::multimap< string_t, string_t > env_map_t
Definition Utility.hh:64
std::string string_t
Definition Utility.hh:63
static EnvSettings * GetInstance()
Definition Utility.hh:68
friend std::ostream & operator<<(std::ostream &os, const EnvSettings &env)
Definition Utility.hh:122
std::mutex mutex_t
Definition Utility.hh:62
const env_map_t & get() const
Definition Utility.hh:119
void PrintEnv(std::ostream &os=std::cout)
Definition Utility.hh:359
void ConsumeParameters(Args &&...)
Definition Utility.hh:44
std::tuple< Tp, std::string, std::string > EnvChoice
Definition Utility.hh:50
Tp GetChoice(const EnvChoiceList< Tp > &_choices, const std::string &str_var)
Definition Utility.hh:315
Tp GetEnv(const std::string &env_id, Tp _default=Tp())
Definition Utility.hh:155
std::set< EnvChoice< Tp > > EnvChoiceList
Definition Utility.hh:55
ScopeDestructor(ScopeDestructor &&rhs) noexcept
Definition Utility.hh:378
ScopeDestructor & operator=(const ScopeDestructor &)=delete
ScopeDestructor(const ScopeDestructor &)=delete
ScopeDestructor(FuncT &&_func)
Definition Utility.hh:369
ScopeDestructor & operator=(ScopeDestructor &&rhs) noexcept
Definition Utility.hh:384