File indexing completed on 2025-01-18 09:57:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #pragma once
0023
0024 #include <cctype>
0025 #include <cstdlib>
0026 #include <functional>
0027 #include <iomanip>
0028 #include <iostream>
0029 #include <map>
0030 #include <mutex>
0031 #include <set>
0032 #include <sstream> // IWYU pragma: keep
0033 #include <string>
0034 #include <tuple>
0035 #include <utility>
0036
0037 namespace PTL
0038 {
0039
0040
0041
0042 template <typename... Args>
0043 void
0044 ConsumeParameters(Args&&...)
0045 {}
0046
0047
0048
0049 template <typename Tp>
0050 using EnvChoice = std::tuple<Tp, std::string, std::string>;
0051
0052
0053
0054 template <typename Tp>
0055 using EnvChoiceList = std::set<EnvChoice<Tp>>;
0056
0057
0058
0059 class EnvSettings
0060 {
0061 public:
0062 using mutex_t = std::mutex;
0063 using string_t = std::string;
0064 using env_map_t = std::multimap<string_t, string_t>;
0065 using env_pair_t = std::pair<string_t, string_t>;
0066
0067 public:
0068 static EnvSettings* GetInstance()
0069 {
0070 static EnvSettings* _instance = new EnvSettings();
0071 return _instance;
0072 }
0073
0074 public:
0075 template <typename Tp>
0076 void insert(const std::string& env_id, Tp val)
0077 {
0078 std::stringstream ss;
0079 ss << std::boolalpha << val;
0080 m_mutex.lock();
0081 if(m_env.find(env_id) != m_env.end())
0082 {
0083 for(const auto& itr : m_env)
0084 if(itr.first == env_id && itr.second == ss.str())
0085 {
0086 m_mutex.unlock();
0087 return;
0088 }
0089 }
0090 m_env.insert(env_pair_t(env_id, ss.str()));
0091 m_mutex.unlock();
0092 }
0093
0094 template <typename Tp>
0095 void insert(const std::string& env_id, EnvChoice<Tp> choice)
0096 {
0097 Tp& val = std::get<0>(choice);
0098 std::string& str_val = std::get<1>(choice);
0099 std::string& descript = std::get<2>(choice);
0100
0101 std::stringstream ss, ss_long;
0102 ss << std::boolalpha << val;
0103 ss_long << std::boolalpha << std::setw(8) << std::left << val << " # (\""
0104 << str_val << "\") " << descript;
0105 m_mutex.lock();
0106 if(m_env.find(env_id) != m_env.end())
0107 {
0108 for(const auto& itr : m_env)
0109 if(itr.first == env_id && itr.second == ss.str())
0110 {
0111 m_mutex.unlock();
0112 return;
0113 }
0114 }
0115 m_env.insert(env_pair_t(env_id, ss_long.str()));
0116 m_mutex.unlock();
0117 }
0118
0119 const env_map_t& get() const { return m_env; }
0120 mutex_t& mutex() const { return m_mutex; }
0121
0122 friend std::ostream& operator<<(std::ostream& os, const EnvSettings& env)
0123 {
0124 std::stringstream filler;
0125 filler.fill('#');
0126 filler << std::setw(90) << "";
0127 std::stringstream ss;
0128 ss << filler.str() << "\n# Environment settings:\n";
0129 env.mutex().lock();
0130 for(const auto& itr : env.get())
0131 {
0132 ss << "# " << std::setw(35) << std::right << itr.first << "\t = \t"
0133 << std::left << itr.second << "\n";
0134 }
0135 env.mutex().unlock();
0136 ss << filler.str();
0137 os << ss.str() << std::endl;
0138 return os;
0139 }
0140
0141 private:
0142 env_map_t m_env;
0143 mutable mutex_t m_mutex;
0144 };
0145
0146
0147
0148
0149
0150
0151
0152
0153 template <typename Tp>
0154 Tp
0155 GetEnv(const std::string& env_id, Tp _default = Tp())
0156 {
0157 char* env_var = std::getenv(env_id.c_str());
0158 if(env_var)
0159 {
0160 std::string str_var = std::string(env_var);
0161 std::istringstream iss(str_var);
0162 Tp var = Tp();
0163 iss >> var;
0164
0165 EnvSettings::GetInstance()->insert<Tp>(env_id, var);
0166 return var;
0167 }
0168
0169 EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
0170
0171
0172 return _default;
0173 }
0174
0175
0176
0177
0178 template <>
0179 inline bool
0180 GetEnv(const std::string& env_id, bool _default)
0181 {
0182 char* env_var = std::getenv(env_id.c_str());
0183 if(env_var)
0184 {
0185 std::string var = std::string(env_var);
0186 bool val = true;
0187 if(var.find_first_not_of("0123456789") == std::string::npos)
0188 val = (bool) atoi(var.c_str());
0189 else
0190 {
0191 for(auto& itr : var)
0192 itr = (char)std::tolower(itr);
0193 if(var == "off" || var == "false")
0194 val = false;
0195 }
0196
0197 EnvSettings::GetInstance()->insert<bool>(env_id, val);
0198 return val;
0199 }
0200
0201 EnvSettings::GetInstance()->insert<bool>(env_id, false);
0202
0203
0204 return _default;
0205 }
0206
0207
0208
0209
0210 template <typename Tp>
0211 Tp
0212 GetEnv(const std::string& env_id, Tp _default, const std::string& msg)
0213 {
0214 char* env_var = std::getenv(env_id.c_str());
0215 if(env_var)
0216 {
0217 std::string str_var = std::string(env_var);
0218 std::istringstream iss(str_var);
0219 Tp var = Tp();
0220 iss >> var;
0221 std::cout << "Environment variable \"" << env_id << "\" enabled with "
0222 << "value == " << var << ". " << msg << std::endl;
0223
0224 EnvSettings::GetInstance()->insert<Tp>(env_id, var);
0225 return var;
0226 }
0227
0228 EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
0229
0230
0231 return _default;
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 template <typename Tp>
0245 Tp
0246 GetEnv(const std::string& env_id, const EnvChoiceList<Tp>& _choices, Tp _default)
0247 {
0248 auto asupper = [](std::string var) {
0249 for(auto& itr : var)
0250 itr = (char)std::toupper(itr);
0251 return var;
0252 };
0253
0254 char* env_var = std::getenv(env_id.c_str());
0255 if(env_var)
0256 {
0257 std::string str_var = std::string(env_var);
0258 std::string upp_var = asupper(str_var);
0259 Tp var = Tp();
0260
0261 for(const auto& itr : _choices)
0262 {
0263 if(asupper(std::get<1>(itr)) == upp_var)
0264 {
0265
0266 EnvSettings::GetInstance()->insert(env_id, itr);
0267 return std::get<0>(itr);
0268 }
0269 }
0270 std::istringstream iss(str_var);
0271 iss >> var;
0272
0273 for(const auto& itr : _choices)
0274 {
0275 if(var == std::get<0>(itr))
0276 {
0277
0278 EnvSettings::GetInstance()->insert(env_id, itr);
0279 return var;
0280 }
0281 }
0282
0283 std::stringstream ss;
0284 ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line "
0285 << __LINE__ << ")! Invalid selection for \"" << env_id
0286 << "\". Valid choices are:\n";
0287 for(const auto& itr : _choices)
0288 ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
0289 << std::get<2>(itr) << ")\n";
0290 std::cerr << ss.str() << std::endl;
0291 abort();
0292 }
0293
0294 std::string _name = "???";
0295 std::string _desc = "description not provided";
0296 for(const auto& itr : _choices)
0297 if(std::get<0>(itr) == _default)
0298 {
0299 _name = std::get<1>(itr);
0300 _desc = std::get<2>(itr);
0301 break;
0302 }
0303
0304
0305 EnvSettings::GetInstance()->insert(env_id, EnvChoice<Tp>(_default, _name, _desc));
0306
0307
0308 return _default;
0309 }
0310
0311
0312
0313 template <typename Tp>
0314 Tp
0315 GetChoice(const EnvChoiceList<Tp>& _choices, const std::string& str_var)
0316 {
0317 auto asupper = [](std::string var) {
0318 for(auto& itr : var)
0319 itr = (char)std::toupper(itr);
0320 return var;
0321 };
0322
0323 std::string upp_var = asupper(str_var);
0324 Tp var = Tp();
0325
0326 for(const auto& itr : _choices)
0327 {
0328 if(asupper(std::get<1>(itr)) == upp_var)
0329 {
0330
0331 return std::get<0>(itr);
0332 }
0333 }
0334 std::istringstream iss(str_var);
0335 iss >> var;
0336
0337 for(const auto& itr : _choices)
0338 {
0339 if(var == std::get<0>(itr))
0340 {
0341
0342 return var;
0343 }
0344 }
0345
0346 std::stringstream ss;
0347 ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line " << __LINE__
0348 << ")! Invalid selection \"" << str_var << "\". Valid choices are:\n";
0349 for(const auto& itr : _choices)
0350 ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
0351 << std::get<2>(itr) << ")\n";
0352 std::cerr << ss.str() << std::endl;
0353 abort();
0354 }
0355
0356
0357
0358 inline void
0359 PrintEnv(std::ostream& os = std::cout)
0360 {
0361 os << (*EnvSettings::GetInstance());
0362 }
0363
0364
0365
0366 struct ScopeDestructor
0367 {
0368 template <typename FuncT>
0369 ScopeDestructor(FuncT&& _func)
0370 : m_functor(std::forward<FuncT>(_func))
0371 {}
0372
0373
0374 ScopeDestructor(const ScopeDestructor&) = delete;
0375 ScopeDestructor& operator=(const ScopeDestructor&) = delete;
0376
0377
0378 ScopeDestructor(ScopeDestructor&& rhs) noexcept
0379 : m_functor(std::move(rhs.m_functor))
0380 {
0381 rhs.m_functor = []() {};
0382 }
0383
0384 ScopeDestructor& operator=(ScopeDestructor&& rhs) noexcept
0385 {
0386 if(this != &rhs)
0387 {
0388 m_functor = std::move(rhs.m_functor);
0389 rhs.m_functor = []() {};
0390 }
0391 return *this;
0392 }
0393
0394 ~ScopeDestructor() { m_functor(); }
0395
0396 private:
0397 std::function<void()> m_functor = []() {};
0398 };
0399
0400
0401
0402 }