#ifndef OMPTARGET_SHARED_ENVIRONMENT_VAR_H
#define OMPTARGET_SHARED_ENVIRONMENT_VAR_H
#include "Debug.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <sstream>
#include <string>
struct StringParser {
template <typename Ty> static bool parse(const char *Value, Ty &Result);
};
template <typename Ty> class Envar {
Ty Data;
bool IsPresent;
bool Initialized;
public:
template <typename... ArgsTy>
static llvm::Expected<Envar> create(ArgsTy &&...Args) {
llvm::Error Err = llvm::Error::success();
Envar Envar(std::forward<ArgsTy>(Args)..., Err);
if (Err)
return std::move(Err);
return std::move(Envar);
}
Envar() : Data(Ty()), IsPresent(false), Initialized(false) {}
Envar(llvm::StringRef Name, Ty Default = Ty())
: Data(Default), IsPresent(false), Initialized(true) {
if (const char *EnvStr = getenv(Name.data())) {
IsPresent = StringParser::parse<Ty>(EnvStr, Data);
if (!IsPresent) {
DP("Ignoring invalid value %s for envar %s\n", EnvStr, Name.data());
Data = Default;
}
}
}
Envar<Ty> &operator=(const Ty &V) {
Data = V;
Initialized = true;
return *this;
}
const Ty &get() const {
if (!Initialized)
FATAL_MESSAGE0(1, "Consulting envar before initialization");
return Data;
}
operator Ty() const { return get(); }
bool isPresent() const { return IsPresent; }
private:
Envar(llvm::StringRef Name, Ty Default, llvm::Error &Err)
: Envar(Name, Default) {
llvm::ErrorAsOutParameter EAO(&Err);
Err = llvm::Error::success();
}
template <typename GetterFunctor, typename SetterFunctor>
Envar(llvm::StringRef Name, GetterFunctor Getter, SetterFunctor Setter,
llvm::Error &Err)
: Data(Ty()), IsPresent(false), Initialized(true) {
llvm::ErrorAsOutParameter EAO(&Err);
Err = init(Name, Getter, Setter);
}
template <typename GetterFunctor, typename SetterFunctor>
llvm::Error init(llvm::StringRef Name, GetterFunctor Getter,
SetterFunctor Setter);
};
using IntEnvar = Envar<int>;
using Int32Envar = Envar<int32_t>;
using Int64Envar = Envar<int64_t>;
using UInt32Envar = Envar<uint32_t>;
using UInt64Envar = Envar<uint64_t>;
using StringEnvar = Envar<std::string>;
using BoolEnvar = Envar<bool>;
template <>
inline bool StringParser::parse(const char *ValueStr, bool &Result) {
std::string Value(ValueStr);
std::transform(Value.begin(), Value.end(), Value.begin(),
[](unsigned char c) { return std::tolower(c); });
if (Value == "true" || Value == "yes" || Value == "on" || Value == "1")
Result = true;
else if (Value == "false" || Value == "no" || Value == "off" || Value == "0")
Result = false;
else
return false;
return true;
}
template <typename Ty>
inline bool StringParser::parse(const char *Value, Ty &Result) {
assert(Value && "Parsed value cannot be null");
std::istringstream Stream(Value);
Stream >> Result;
return !Stream.fail();
}
template <typename Ty>
template <typename GetterFunctor, typename SetterFunctor>
inline llvm::Error Envar<Ty>::init(llvm::StringRef Name, GetterFunctor Getter,
SetterFunctor Setter) {
Ty Default;
if (llvm::Error Err = Getter(Default))
return Err;
if (const char *EnvStr = getenv(Name.data())) {
IsPresent = StringParser::parse<Ty>(EnvStr, Data);
if (IsPresent) {
llvm::Error Err = Setter(Data);
if (Err) {
IsPresent = false;
Data = Default;
DP("Setter of envar %s failed, resetting to %s\n", Name.data(),
std::to_string(Data).data());
consumeError(std::move(Err));
}
} else {
DP("Ignoring invalid value %s for envar %s\n", EnvStr, Name.data());
Data = Default;
}
} else {
Data = Default;
}
return llvm::Error::success();
}
#endif