Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_EnvVariables.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teuchos_EnvVariables.hpp"
11 
12 #include <stddef.h>
13 #include <string>
14 
15 #include <cstdlib> // std::getenv
16 #include <map>
17 #include <sstream>
18 #include <stdexcept>
19 #include <string>
20 #include <vector>
21 
22 #include "Teuchos_StrUtils.hpp"
24 
25 namespace Teuchos {
26 
27 namespace {
28 
29 enum EnvironmentVariableState {
30  EnvironmentVariableIsSet_ON,
31  EnvironmentVariableIsSet_OFF,
32  EnvironmentVariableIsSet,
33  EnvironmentVariableIsNotSet
34 };
35 
36 EnvironmentVariableState
37 environmentVariableState(const std::string &environmentVariableValue) {
38  std::string v = StrUtils::allCaps(environmentVariableValue);
39  if (v == "1" || v == "YES" || v == "TRUE" || v == "ON")
40  // Environment variable is "ON"
41  return EnvironmentVariableIsSet_ON;
42  else if (v == "0" || v == "NO" || v == "FALSE" || v == "OFF")
43  // Environment variable is "OFF"
44  return EnvironmentVariableIsSet_OFF;
45  // Environment has some other non-boolean value
46  return EnvironmentVariableIsSet;
47 }
48 
49 void setEnvironmentVariableMap(
50  const char environmentVariableName[],
51  std::map<std::string, std::map<std::string, bool>> &valsMap,
52  const bool defaultValue) {
53  using std::getenv;
54  using std::map;
55  using std::string;
56  using std::vector;
57 
58  // Set the default value for this variable
59  valsMap[environmentVariableName] =
60  map<string, bool>{{"DEFAULT", defaultValue}};
61 
62  const char *varVal = getenv(environmentVariableName);
63  if (varVal == nullptr) {
64  // Environment variable is not set, use the default value for any named
65  // variants
66  return;
67  }
68 
69  // Variable is not empty.
70  const string varStr(varVal);
71  // vector<string> names;
72  // split(varStr, [&](const string &x) { names.push_back(x); });
73  auto names = StrUtils::splitString(varStr, ',');
74  for (auto const &name : names) {
75  auto state = environmentVariableState(name);
76  if (state == EnvironmentVariableIsSet_ON) {
77  // Environment variable was set as ENVAR_NAME=[1,YES,TRUE,ON]
78  // Global value takes precedence
79  valsMap[environmentVariableName]["DEFAULT"] = true;
80  } else if (state == EnvironmentVariableIsSet_OFF) {
81  // Environment variable was set as ENVAR_NAME=[0,NO,FALSE,OFF]
82  // Global value takes precedence
83  valsMap[environmentVariableName]["DEFAULT"] = false;
84  } else {
85  // Environment variable was set as ENVAR_NAME=...:name:...
86  // So we set the mapping true for this named variant
87  valsMap[environmentVariableName][name] = true;
88  }
89  }
90  return;
91 }
92 } // namespace
93 
94 template <typename T>
95 T getEnvironmentVariable(const std::string_view environmentVariableName,
96  const T defaultValue) {
97  const char *varVal = std::getenv(environmentVariableName.data());
98  if (varVal == nullptr) {
99  return defaultValue;
100  } else {
101  std::stringstream ss(varVal);
102  T parsed;
103  ss >> parsed;
104 
106  !ss, std::out_of_range,
107  "Environment variable \""
108  << environmentVariableName << "\" has a value " << varVal
109  << " that cannot be parsed as a " << typeid(T).name() << ".");
110 
111  return parsed;
112  }
113 }
114 
115 // full specialization of bool to preserve historical parsing behavior
116 template <>
118  const std::string_view environmentVariableName, const bool defaultValue) {
119  const char *varVal = std::getenv(environmentVariableName.data());
120  bool retVal = defaultValue;
121  if (varVal != nullptr) {
122  auto state = environmentVariableState(std::string(varVal));
123  if (state == EnvironmentVariableIsSet_ON)
124  retVal = true;
125  else if (state == EnvironmentVariableIsSet_OFF)
126  retVal = false;
127  }
128  return retVal;
129 }
130 
136 template <>
137 size_t
138 getEnvironmentVariable<size_t>(const std::string_view environmentVariableName,
139  const size_t defaultValue) {
140  const char *varVal = std::getenv(environmentVariableName.data());
141  if (varVal == nullptr) {
142  return defaultValue;
143  } else {
144  long long val = std::stoll(StrUtils::allCaps(varVal));
145  if (val < static_cast<long long>(0)) {
146  // If negative - user has requested threshold be lifted
147  return std::numeric_limits<size_t>::max();
148  }
149  if (sizeof(long long) > sizeof(size_t)) {
150  // It's hard to test this code, but I want to try writing it
151  // at least, in case we ever have to run on 32-bit machines or
152  // machines with sizeof(long long)=16 and sizeof(size_t)=8.
153  constexpr long long maxSizeT =
154  static_cast<long long>(std::numeric_limits<size_t>::max());
156  val > maxSizeT, std::out_of_range,
157  "Environment variable \""
158  << environmentVariableName << "\" has a value " << val
159  << " larger than the largest size_t value " << maxSizeT << ".");
160  }
161  return static_cast<size_t>(val);
162  }
163 }
164 
166  const char name[], bool &initialized, const char environmentVariableName[],
167  const bool defaultValue) {
168  static std::map<std::string, std::map<std::string, bool>> namedVariableMap_;
169  if (!initialized) {
170  setEnvironmentVariableMap(environmentVariableName, namedVariableMap_,
171  defaultValue);
172  initialized = true;
173  }
174  auto thisEnvironmentVariableMap = namedVariableMap_[environmentVariableName];
175  auto thisEnvironmentVariable = thisEnvironmentVariableMap.find(name);
176  if (thisEnvironmentVariable != thisEnvironmentVariableMap.end())
177  return thisEnvironmentVariable->second;
178  return thisEnvironmentVariableMap["DEFAULT"];
179 }
180 
181 template <typename T>
183  T &value, bool &initialized, const std::string_view environmentVariableName,
184  const T defaultValue) {
185  if (!initialized) {
186  value = getEnvironmentVariable<T>(environmentVariableName, defaultValue);
187  initialized = true;
188  }
189  return value;
190 }
191 
192 
193 template std::string idempotentlyGetEnvironmentVariable<std::string>(std::string&, bool&, const std::string_view, const std::string);
194 template int idempotentlyGetEnvironmentVariable<int>(int&, bool&, const std::string_view, const int);
195 template unsigned long idempotentlyGetEnvironmentVariable<unsigned long>(unsigned long&, bool&, const std::string_view, const unsigned long);
196 template bool idempotentlyGetEnvironmentVariable<bool>(bool&, bool&, const std::string_view, const bool);
197 template unsigned long long idempotentlyGetEnvironmentVariable<unsigned long long>(unsigned long long&, bool&, const std::string_view, const unsigned long long);
198 
199 } // namespace Teuchos
static std::string allCaps(const std::string &str)
Converts a std::string to all upper case.
template unsigned long long idempotentlyGetEnvironmentVariable< unsigned long long >(unsigned long long &, bool &, const std::string_view, const unsigned long long)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
bool idempotentlyGetNamedEnvironmentVariableAsBool(const char name[], bool &initialized, const char environmentVariableName[], const bool defaultValue)
template unsigned long idempotentlyGetEnvironmentVariable< unsigned long >(unsigned long &, bool &, const std::string_view, const unsigned long)
A std::string utilities class for Teuchos.
T idempotentlyGetEnvironmentVariable(T &value, bool &initialized, const std::string_view environmentVariableName, const T defaultValue)
Read a variable from the environment. Example usage:
static Array< std::string > splitString(const std::string_view s, const char sep= ',')
Split an input std::string using a seperator char sep.
Standard test and throw macros.
template bool idempotentlyGetEnvironmentVariable< bool >(bool &, bool &, const std::string_view, const bool)
template int idempotentlyGetEnvironmentVariable< int >(int &, bool &, const std::string_view, const int)
size_t getEnvironmentVariable< size_t >(const std::string_view environmentVariableName, const size_t defaultValue)
T getEnvironmentVariable(const std::string_view environmentVariableName, const T defaultValue)
bool getEnvironmentVariable< bool >(const std::string_view environmentVariableName, const bool defaultValue)