125 lines
6.1 KiB
C++
125 lines
6.1 KiB
C++
#pragma once
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
namespace cpputils {
|
|
namespace env_var {
|
|
|
|
class EnvVarRegistry {
|
|
public:
|
|
static EnvVarRegistry& instance() {
|
|
static EnvVarRegistry inst;
|
|
return inst;
|
|
}
|
|
|
|
void register_var(std::string const& name, char const* default_val) {
|
|
if (vars_.find(name) != vars_.end()) {
|
|
std::cerr << "ENV VAR \"" << name << "\" already registered!";
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
vars_.emplace(name, std::string(default_val));
|
|
}
|
|
|
|
template <typename T>
|
|
void register_var(std::string const& name, T const& default_val) {
|
|
static_assert(std::is_arithmetic_v<T>,
|
|
"Only arithmetic types supported here");
|
|
if (vars_.find(name) != vars_.end()) {
|
|
std::cerr << "ENV VAR \"" << name << "\" already registered!";
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
vars_.emplace(name, std::to_string(default_val));
|
|
}
|
|
|
|
std::unordered_map<std::string, std::string> const& get_vars() const {
|
|
return vars_;
|
|
}
|
|
|
|
private:
|
|
std::unordered_map<std::string, std::string> vars_;
|
|
|
|
public:
|
|
struct EnvVarAutoRegister {
|
|
template <typename T>
|
|
EnvVarAutoRegister(char const* name, T const& default_value) {
|
|
EnvVarRegistry::instance().register_var(name, default_value);
|
|
}
|
|
};
|
|
};
|
|
|
|
#define DEFINE_ENV_VAR_STRING_LEN(name, DEFAULT_VALUE, MIN_LEN) \
|
|
namespace EnvVars { \
|
|
struct name { \
|
|
static constexpr char const* DEFAULT = DEFAULT_VALUE; \
|
|
static constexpr char const* NAME = #name; \
|
|
static char const* GET() { \
|
|
auto c = std::getenv(#name); \
|
|
if (c) { \
|
|
if (std::strlen(c) >= MIN_LEN) { \
|
|
return c; \
|
|
} \
|
|
} \
|
|
return DEFAULT_VALUE; \
|
|
} \
|
|
static inline ::cpputils::env_var::EnvVarRegistry::EnvVarAutoRegister \
|
|
_env_register{#name, DEFAULT_VALUE}; \
|
|
}; \
|
|
}
|
|
|
|
#define DEFINE_ENV_VAR_STRING(name, DEFAULT_VALUE) \
|
|
DEFINE_ENV_VAR_STRING_LEN(name, DEFAULT_VALUE, 1)
|
|
|
|
#define DEFINE_ENV_VAR_INT(TYPE, name, DEFAULT_VALUE) \
|
|
namespace EnvVars { \
|
|
struct name { \
|
|
static constexpr TYPE DEFAULT = DEFAULT_VALUE; \
|
|
static constexpr char const* NAME = #name; \
|
|
static TYPE GET() { \
|
|
constexpr auto lower_bound = std::numeric_limits<TYPE>::min(); \
|
|
constexpr auto upper_bound = std::numeric_limits<TYPE>::max(); \
|
|
auto c = std::getenv(#name); \
|
|
if (c) { \
|
|
if (std::strlen(c) > 0) { \
|
|
try { \
|
|
if constexpr (std::is_unsigned_v<TYPE>) { \
|
|
const char* p = c; \
|
|
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') { \
|
|
++p; \
|
|
} \
|
|
if (*p == '-') { \
|
|
return lower_bound; \
|
|
} \
|
|
auto x = std::stoull(c); \
|
|
if (x > upper_bound) { \
|
|
return upper_bound; \
|
|
} else { \
|
|
return static_cast<TYPE>(x); \
|
|
} \
|
|
} else { \
|
|
auto x = std::stoll(c); \
|
|
if (x > upper_bound) { \
|
|
return upper_bound; \
|
|
} else if (x < lower_bound) { \
|
|
return lower_bound; \
|
|
} else { \
|
|
return static_cast<TYPE>(x); \
|
|
} \
|
|
} \
|
|
} catch (...) {} \
|
|
} \
|
|
} \
|
|
return DEFAULT_VALUE; \
|
|
} \
|
|
static inline ::cpputils::env_var::EnvVarRegistry::EnvVarAutoRegister \
|
|
_env_register{#name, DEFAULT_VALUE}; \
|
|
}; \
|
|
}
|
|
|
|
} // namespace env_var
|
|
} // namespace cpputils
|