Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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