Warning: This file is not a C or C++ file. It does not have highlighting.

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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9//===----------------------------------------------------------------------===//
10
11#ifndef OMPTARGET_SHARED_ENVIRONMENT_VAR_H
12#define OMPTARGET_SHARED_ENVIRONMENT_VAR_H
13
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 with
29/// 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 safely
38 /// creates envars using fallible constructors. See the constructors to know
39 /// 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 merely
50 /// 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 will
54 /// take the value read from the environment variable, or the default if it
55 /// 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. This
96 /// way, the constructor can be used by the Envar::create() static function
97 /// 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. The
105 /// Envar object will take the value read from the environment variable if
106 /// this value is accepted by the setter function. Otherwise, the getter
107 /// function will be executed to get the default value. The getter should be
108 /// of the form Error GetterFunctionTy(Ty &Value) and the setter should
109 /// be of the form Error SetterFunctionTy(Ty Value). This constructor has a
110 /// private visibility because is a fallible constructor. Please use the
111 /// 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 else
148 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 as
180 // 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_H
199

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of offload/include/Shared/EnvironmentVar.h