Geant4-11
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 "PTL/Types.hh"
25
26#include <chrono>
27#include <cstdlib>
28#include <iomanip>
29#include <iostream>
30#include <map>
31#include <mutex>
32#include <set>
33#include <sstream>
34#include <string>
35#include <tuple>
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:
63 typedef std::string string_t;
64 typedef std::multimap<string_t, string_t> env_map_t;
65 typedef std::pair<string_t, string_t> env_pair_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:
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 = 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 = 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 = 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
366} // namespace PTL
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::mutex mutex_t
Definition: Utility.hh:62
std::string string_t
Definition: Utility.hh:63
std::pair< string_t, string_t > env_pair_t
Definition: Utility.hh:65
static EnvSettings * GetInstance()
Definition: Utility.hh:68
friend std::ostream & operator<<(std::ostream &os, const EnvSettings &env)
Definition: Utility.hh:122
const env_map_t & get() const
Definition: Utility.hh:119
env_map_t m_env
Definition: Utility.hh:142
std::multimap< string_t, string_t > env_map_t
Definition: Utility.hh:64
mutex_t m_mutex
Definition: Utility.hh:143
Definition: AutoLock.hh:254
void PrintEnv(std::ostream &os=std::cout)
Definition: Utility.hh:359
std::set< EnvChoice< Tp > > EnvChoiceList
Definition: Utility.hh:55
Tp GetChoice(const EnvChoiceList< Tp > &_choices, const std::string str_var)
Definition: Utility.hh:315
std::tuple< Tp, std::string, std::string > EnvChoice
Definition: Utility.hh:50
Tp GetEnv(const std::string &env_id, Tp _default=Tp())
Definition: Utility.hh:155
void ConsumeParameters(Args...)
Definition: Utility.hh:44