Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:47

0001 //
0002 // MIT License
0003 // Copyright (c) 2020 Jonathan R. Madsen
0004 // Permission is hereby granted, free of charge, to any person obtaining a copy
0005 // of this software and associated documentation files (the "Software"), to deal
0006 // in the Software without restriction, including without limitation the rights
0007 // to use, copy, modify, merge, publish, distribute, sublicense, and
0008 // copies of the Software, and to permit persons to whom the Software is
0009 // furnished to do so, subject to the following conditions:
0010 // The above copyright notice and this permission notice shall be included in
0011 // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
0012 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
0013 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
0014 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
0015 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0016 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0017 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0018 //
0019 // Global utility functions
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 // use this function to get rid of "unused parameter" warnings
0041 //
0042 template <typename... Args>
0043 void
0044 ConsumeParameters(Args&&...)
0045 {}
0046 
0047 //--------------------------------------------------------------------------------------//
0048 // a non-string environment option with a string identifier
0049 template <typename Tp>
0050 using EnvChoice = std::tuple<Tp, std::string, std::string>;
0051 
0052 //--------------------------------------------------------------------------------------//
0053 // list of environment choices with non-string and string identifiers
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 //  use this function to get an environment variable setting +
0148 //  a default if not defined, e.g.
0149 //      int num_threads =
0150 //          GetEnv<int>("FORCENUMBEROFTHREADS",
0151 //                          std::thread::hardware_concurrency());
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         // record value defined by environment
0165         EnvSettings::GetInstance()->insert<Tp>(env_id, var);
0166         return var;
0167     }
0168     // record default value
0169     EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
0170 
0171     // return default if not specified in environment
0172     return _default;
0173 }
0174 
0175 //--------------------------------------------------------------------------------------//
0176 //  overload for boolean
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         // record value defined by environment
0197         EnvSettings::GetInstance()->insert<bool>(env_id, val);
0198         return val;
0199     }
0200     // record default value
0201     EnvSettings::GetInstance()->insert<bool>(env_id, false);
0202 
0203     // return default if not specified in environment
0204     return _default;
0205 }
0206 
0207 //--------------------------------------------------------------------------------------//
0208 //  overload for GetEnv + message when set
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         // record value defined by environment
0224         EnvSettings::GetInstance()->insert<Tp>(env_id, var);
0225         return var;
0226     }
0227     // record default value
0228     EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
0229 
0230     // return default if not specified in environment
0231     return _default;
0232 }
0233 
0234 //--------------------------------------------------------------------------------------//
0235 //  use this function to get an environment variable setting from set of choices
0236 //
0237 //      EnvChoiceList<int> choices =
0238 //              { EnvChoice<int>(NN,     "NN",     "nearest neighbor interpolation"),
0239 //                EnvChoice<int>(LINEAR, "LINEAR", "bilinear interpolation"),
0240 //                EnvChoice<int>(CUBIC,  "CUBIC",  "bicubic interpolation") };
0241 //
0242 //      int eInterp = GetEnv<int>("INTERPOLATION", choices, CUBIC);
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         // check to see if string matches a choice
0261         for(const auto& itr : _choices)
0262         {
0263             if(asupper(std::get<1>(itr)) == upp_var)
0264             {
0265                 // record value defined by environment
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         // check to see if string matches a choice
0273         for(const auto& itr : _choices)
0274         {
0275             if(var == std::get<0>(itr))
0276             {
0277                 // record value defined by environment
0278                 EnvSettings::GetInstance()->insert(env_id, itr);
0279                 return var;
0280             }
0281         }
0282         // the value set in env did not match any choices
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     // record default value
0305     EnvSettings::GetInstance()->insert(env_id, EnvChoice<Tp>(_default, _name, _desc));
0306 
0307     // return default if not specified in environment
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     // check to see if string matches a choice
0326     for(const auto& itr : _choices)
0327     {
0328         if(asupper(std::get<1>(itr)) == upp_var)
0329         {
0330             // record value defined by environment
0331             return std::get<0>(itr);
0332         }
0333     }
0334     std::istringstream iss(str_var);
0335     iss >> var;
0336     // check to see if string matches a choice
0337     for(const auto& itr : _choices)
0338     {
0339         if(var == std::get<0>(itr))
0340         {
0341             // record value defined by environment
0342             return var;
0343         }
0344     }
0345     // the value set in env did not match any choices
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     // delete copy operations
0374     ScopeDestructor(const ScopeDestructor&) = delete;
0375     ScopeDestructor& operator=(const ScopeDestructor&) = delete;
0376 
0377     // allow move operations
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 }  // namespace PTL