forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[OpenMP][NFC] Separate Envar (environment variable) handling (llvm#73994
- Loading branch information
Showing
8 changed files
with
212 additions
and
196 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
//===-- Shared/EnvironmentVar.h - Environment variable handling -*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#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> | ||
|
||
/// Utility class for parsing strings to other types. | ||
struct StringParser { | ||
/// Parse a string to another type. | ||
template <typename Ty> static bool parse(const char *Value, Ty &Result); | ||
}; | ||
|
||
/// Class for reading and checking environment variables. Currently working with | ||
/// integer, floats, std::string and bool types. | ||
template <typename Ty> class Envar { | ||
Ty Data; | ||
bool IsPresent; | ||
bool Initialized; | ||
|
||
public: | ||
/// Auxiliary function to safely create envars. This static function safely | ||
/// creates envars using fallible constructors. See the constructors to know | ||
/// more details about the creation parameters. | ||
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); | ||
} | ||
|
||
/// Create an empty envar. Cannot be consulted. This constructor is merely | ||
/// for convenience. This constructor is not fallible. | ||
Envar() : Data(Ty()), IsPresent(false), Initialized(false) {} | ||
|
||
/// Create an envar with a name and an optional default. The Envar object will | ||
/// take the value read from the environment variable, or the default if it | ||
/// was not set or not correct. This constructor is not fallible. | ||
Envar(llvm::StringRef Name, Ty Default = Ty()) | ||
: Data(Default), IsPresent(false), Initialized(true) { | ||
|
||
if (const char *EnvStr = getenv(Name.data())) { | ||
// Check whether the envar is defined and valid. | ||
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; | ||
} | ||
|
||
/// Get the definitive value. | ||
const Ty &get() const { | ||
// Throw a runtime error in case this envar is not initialized. | ||
if (!Initialized) | ||
FATAL_MESSAGE0(1, "Consulting envar before initialization"); | ||
|
||
return Data; | ||
} | ||
|
||
/// Get the definitive value. | ||
operator Ty() const { return get(); } | ||
|
||
/// Indicate whether the environment variable was defined and valid. | ||
bool isPresent() const { return IsPresent; } | ||
|
||
private: | ||
/// This constructor should never fail but we provide it for convenience. This | ||
/// way, the constructor can be used by the Envar::create() static function | ||
/// to safely create this kind of envars. | ||
Envar(llvm::StringRef Name, Ty Default, llvm::Error &Err) | ||
: Envar(Name, Default) { | ||
llvm::ErrorAsOutParameter EAO(&Err); | ||
Err = llvm::Error::success(); | ||
} | ||
|
||
/// Create an envar with a name, getter function and a setter function. The | ||
/// Envar object will take the value read from the environment variable if | ||
/// this value is accepted by the setter function. Otherwise, the getter | ||
/// function will be executed to get the default value. The getter should be | ||
/// of the form Error GetterFunctionTy(Ty &Value) and the setter should | ||
/// be of the form Error SetterFunctionTy(Ty Value). This constructor has a | ||
/// private visibility because is a fallible constructor. Please use the | ||
/// Envar::create() static function to safely create this object instead. | ||
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); | ||
}; | ||
|
||
/// Define some common envar types. | ||
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); | ||
|
||
// Convert the string to lowercase. | ||
std::transform(Value.begin(), Value.end(), Value.begin(), | ||
[](unsigned char c) { return std::tolower(c); }); | ||
|
||
// May be implemented with fancier C++ features, but let's keep it simple. | ||
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; | ||
|
||
// Parsed correctly. | ||
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) { | ||
// Get the default value. | ||
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) { | ||
// Check whether the envar value is actually valid. | ||
llvm::Error Err = Setter(Data); | ||
if (Err) { | ||
// The setter reported an invalid value. Mark the user-defined value as | ||
// not present and reset to the getter value (default). | ||
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 // OMPTARGET_SHARED_ENVIRONMENT_VAR_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.