brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 82f434e Raw
199 lines · c
1//===-- Shared/EnvironmentVar.h - Environment variable handling -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//===----------------------------------------------------------------------===//10 11#ifndef OMPTARGET_SHARED_ENVIRONMENT_VAR_H12#define OMPTARGET_SHARED_ENVIRONMENT_VAR_H13 14#include "Debug.h"15 16#include "llvm/ADT/StringRef.h"17#include "llvm/Support/Error.h"18 19#include <sstream>20#include <string>21 22/// Utility class for parsing strings to other types.23struct StringParser {24  /// Parse a string to another type.25  template <typename Ty> static bool parse(const char *Value, Ty &Result);26};27 28/// Class for reading and checking environment variables. Currently working with29/// integer, floats, std::string and bool types.30template <typename Ty> class Envar {31  llvm::StringRef Name;32  Ty Data;33  bool IsPresent;34  bool Initialized;35 36public:37  /// Auxiliary function to safely create envars. This static function safely38  /// creates envars using fallible constructors. See the constructors to know39  /// more details about the creation parameters.40  template <typename... ArgsTy>41  static llvm::Expected<Envar> create(ArgsTy &&...Args) {42    llvm::Error Err = llvm::Error::success();43    Envar Envar(std::forward<ArgsTy>(Args)..., Err);44    if (Err)45      return std::move(Err);46    return std::move(Envar);47  }48 49  /// Create an empty envar. Cannot be consulted. This constructor is merely50  /// for convenience. This constructor is not fallible.51  Envar() : Data(Ty()), IsPresent(false), Initialized(false) {}52 53  /// Create an envar with a name and an optional default. The Envar object will54  /// take the value read from the environment variable, or the default if it55  /// was not set or not correct. This constructor is not fallible.56  Envar(llvm::StringRef Name, Ty Default = Ty())57      : Name(Name), Data(Default), IsPresent(false), Initialized(true) {58 59    if (const char *EnvStr = getenv(Name.data())) {60      // Check whether the envar is defined and valid.61      IsPresent = StringParser::parse<Ty>(EnvStr, Data);62 63      if (!IsPresent) {64        DP("Ignoring invalid value %s for envar %s\n", EnvStr, Name.data());65        Data = Default;66      }67    }68  }69 70  Envar<Ty> &operator=(const Ty &V) {71    Data = V;72    Initialized = true;73    return *this;74  }75 76  /// Get the definitive value.77  const Ty &get() const {78    // Throw a runtime error in case this envar is not initialized.79    if (!Initialized)80      FATAL_MESSAGE0(1, "Consulting envar before initialization");81 82    return Data;83  }84 85  /// Get the definitive value.86  operator Ty() const { return get(); }87 88  /// Return the environment variable name.89  llvm::StringRef getName() const { return Name; }90 91  /// Indicate whether the environment variable was defined and valid.92  bool isPresent() const { return IsPresent; }93 94private:95  /// This constructor should never fail but we provide it for convenience. This96  /// way, the constructor can be used by the Envar::create() static function97  /// to safely create this kind of envars.98  Envar(llvm::StringRef Name, Ty Default, llvm::Error &Err)99      : Envar(Name, Default) {100    llvm::ErrorAsOutParameter EAO(&Err);101    Err = llvm::Error::success();102  }103 104  /// Create an envar with a name, getter function and a setter function. The105  /// Envar object will take the value read from the environment variable if106  /// this value is accepted by the setter function. Otherwise, the getter107  /// function will be executed to get the default value. The getter should be108  /// of the form Error GetterFunctionTy(Ty &Value) and the setter should109  /// be of the form Error SetterFunctionTy(Ty Value). This constructor has a110  /// private visibility because is a fallible constructor. Please use the111  /// Envar::create() static function to safely create this object instead.112  template <typename GetterFunctor, typename SetterFunctor>113  Envar(llvm::StringRef Name, GetterFunctor Getter, SetterFunctor Setter,114        llvm::Error &Err)115      : Data(Ty()), IsPresent(false), Initialized(true) {116    llvm::ErrorAsOutParameter EAO(&Err);117    Err = init(Name, Getter, Setter);118  }119 120  template <typename GetterFunctor, typename SetterFunctor>121  llvm::Error init(llvm::StringRef Name, GetterFunctor Getter,122                   SetterFunctor Setter);123};124 125/// Define some common envar types.126using IntEnvar = Envar<int>;127using Int32Envar = Envar<int32_t>;128using Int64Envar = Envar<int64_t>;129using UInt32Envar = Envar<uint32_t>;130using UInt64Envar = Envar<uint64_t>;131using StringEnvar = Envar<std::string>;132using BoolEnvar = Envar<bool>;133 134template <>135inline bool StringParser::parse(const char *ValueStr, bool &Result) {136  std::string Value(ValueStr);137 138  // Convert the string to lowercase.139  std::transform(Value.begin(), Value.end(), Value.begin(),140                 [](unsigned char c) { return std::tolower(c); });141 142  // May be implemented with fancier C++ features, but let's keep it simple.143  if (Value == "true" || Value == "yes" || Value == "on" || Value == "1")144    Result = true;145  else if (Value == "false" || Value == "no" || Value == "off" || Value == "0")146    Result = false;147  else148    return false;149 150  // Parsed correctly.151  return true;152}153 154template <typename Ty>155inline bool StringParser::parse(const char *Value, Ty &Result) {156  assert(Value && "Parsed value cannot be null");157 158  std::istringstream Stream(Value);159  Stream >> Result;160 161  return !Stream.fail();162}163 164template <typename Ty>165template <typename GetterFunctor, typename SetterFunctor>166inline llvm::Error Envar<Ty>::init(llvm::StringRef Name, GetterFunctor Getter,167                                   SetterFunctor Setter) {168  // Get the default value.169  Ty Default;170  if (llvm::Error Err = Getter(Default))171    return Err;172 173  if (const char *EnvStr = getenv(Name.data())) {174    IsPresent = StringParser::parse<Ty>(EnvStr, Data);175    if (IsPresent) {176      // Check whether the envar value is actually valid.177      llvm::Error Err = Setter(Data);178      if (Err) {179        // The setter reported an invalid value. Mark the user-defined value as180        // not present and reset to the getter value (default).181        IsPresent = false;182        Data = Default;183        DP("Setter of envar %s failed, resetting to %s\n", Name.data(),184           std::to_string(Data).data());185        consumeError(std::move(Err));186      }187    } else {188      DP("Ignoring invalid value %s for envar %s\n", EnvStr, Name.data());189      Data = Default;190    }191  } else {192    Data = Default;193  }194 195  return llvm::Error::success();196}197 198#endif // OMPTARGET_SHARED_ENVIRONMENT_VAR_H199