1 //
2 // Copyright 2019 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
17 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
18
19 #include <stddef.h>
20 #include <stdint.h>
21
22 #include <memory>
23 #include <string>
24 #include <typeinfo>
25
26 #include "absl/base/config.h"
27 #include "absl/base/macros.h"
28 #include "absl/flags/config.h"
29 #include "absl/flags/marshalling.h"
30 #include "absl/strings/string_view.h"
31 #include "absl/types/optional.h"
32
33 namespace absl {
34 ABSL_NAMESPACE_BEGIN
35 namespace flags_internal {
36
37 // An alias for flag static type id. Values of type identify the flag value type
38 // simialarly to typeid(T), but without relying on RTTI being available. In most
39 // cases this id is enough to uniquely identify the flag's value type. In a few
40 // cases we'll have to resort to using actual RTTI implementation if it is
41 // available.
42 using FlagStaticTypeId = void* (*)();
43
44 // Address of this function template is used in current implementation as a flag
45 // static type id.
46 template <typename T>
FlagStaticTypeIdGen()47 void* FlagStaticTypeIdGen() {
48 #if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
49 return const_cast<std::type_info*>(&typeid(T));
50 #else
51 return nullptr;
52 #endif
53 }
54
55 // Options that control SetCommandLineOptionWithMode.
56 enum FlagSettingMode {
57 // update the flag's value unconditionally (can call this multiple times).
58 SET_FLAGS_VALUE,
59 // update the flag's value, but *only if* it has not yet been updated
60 // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef".
61 SET_FLAG_IF_DEFAULT,
62 // set the flag's default value to this. If the flag has not been updated
63 // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef")
64 // change the flag's current value to the new default value as well.
65 SET_FLAGS_DEFAULT
66 };
67
68 // Options that control SetFromString: Source of a value.
69 enum ValueSource {
70 // Flag is being set by value specified on a command line.
71 kCommandLine,
72 // Flag is being set by value specified in the code.
73 kProgrammaticChange,
74 };
75
76 // Handle to FlagState objects. Specific flag state objects will restore state
77 // of a flag produced this flag state from method CommandLineFlag::SaveState().
78 class FlagStateInterface {
79 public:
~FlagStateInterface()80 virtual ~FlagStateInterface() {}
81
82 // Restores the flag originated this object to the saved state.
83 virtual void Restore() const = 0;
84 };
85
86 // Holds all information for a flag.
87 class CommandLineFlag {
88 public:
89 constexpr CommandLineFlag() = default;
90
91 // Not copyable/assignable.
92 CommandLineFlag(const CommandLineFlag&) = delete;
93 CommandLineFlag& operator=(const CommandLineFlag&) = delete;
94
95 // Non-polymorphic access methods.
96
97 // Return true iff flag has type T.
98 template <typename T>
IsOfType()99 inline bool IsOfType() const {
100 return TypeId() == &flags_internal::FlagStaticTypeIdGen<T>;
101 }
102
103 // Attempts to retrieve the flag value. Returns value on success,
104 // absl::nullopt otherwise.
105 template <typename T>
Get()106 absl::optional<T> Get() const {
107 if (IsRetired() || !IsOfType<T>()) {
108 return absl::nullopt;
109 }
110
111 // Implementation notes:
112 //
113 // We are wrapping a union around the value of `T` to serve three purposes:
114 //
115 // 1. `U.value` has correct size and alignment for a value of type `T`
116 // 2. The `U.value` constructor is not invoked since U's constructor does
117 // not do it explicitly.
118 // 3. The `U.value` destructor is invoked since U's destructor does it
119 // explicitly. This makes `U` a kind of RAII wrapper around non default
120 // constructible value of T, which is destructed when we leave the
121 // scope. We do need to destroy U.value, which is constructed by
122 // CommandLineFlag::Read even though we left it in a moved-from state
123 // after std::move.
124 //
125 // All of this serves to avoid requiring `T` being default constructible.
126 union U {
127 T value;
128 U() {}
129 ~U() { value.~T(); }
130 };
131 U u;
132
133 Read(&u.value);
134 return std::move(u.value);
135 }
136
137 // Polymorphic access methods
138
139 // Returns name of this flag.
140 virtual absl::string_view Name() const = 0;
141 // Returns name of the file where this flag is defined.
142 virtual std::string Filename() const = 0;
143 // Returns name of the flag's value type for some built-in types or empty
144 // std::string.
145 virtual absl::string_view Typename() const = 0;
146 // Returns help message associated with this flag.
147 virtual std::string Help() const = 0;
148 // Returns true iff this object corresponds to retired flag.
IsRetired()149 virtual bool IsRetired() const { return false; }
150 // Returns true iff this is a handle to an Abseil Flag.
IsAbseilFlag()151 virtual bool IsAbseilFlag() const { return true; }
152 // Returns id of the flag's value type.
153 virtual FlagStaticTypeId TypeId() const = 0;
154 virtual bool IsModified() const = 0;
155 virtual bool IsSpecifiedOnCommandLine() const = 0;
156 virtual std::string DefaultValue() const = 0;
157 virtual std::string CurrentValue() const = 0;
158
159 // Interfaces to operate on validators.
160 virtual bool ValidateInputValue(absl::string_view value) const = 0;
161
162 // Interface to save flag to some persistent state. Returns current flag state
163 // or nullptr if flag does not support saving and restoring a state.
164 virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
165
166 // Sets the value of the flag based on specified std::string `value`. If the flag
167 // was successfully set to new value, it returns true. Otherwise, sets `error`
168 // to indicate the error, leaves the flag unchanged, and returns false. There
169 // are three ways to set the flag's value:
170 // * Update the current flag value
171 // * Update the flag's default value
172 // * Update the current flag value if it was never set before
173 // The mode is selected based on `set_mode` parameter.
174 virtual bool SetFromString(absl::string_view value,
175 flags_internal::FlagSettingMode set_mode,
176 flags_internal::ValueSource source,
177 std::string* error) = 0;
178
179 // Checks that flags default value can be converted to std::string and back to the
180 // flag's value type.
181 virtual void CheckDefaultValueParsingRoundtrip() const = 0;
182
183 protected:
184 ~CommandLineFlag() = default;
185
186 private:
187 // Copy-construct a new value of the flag's type in a memory referenced by
188 // the dst based on the current flag's value.
189 virtual void Read(void* dst) const = 0;
190 };
191
192 // This macro is the "source of truth" for the list of supported flag built-in
193 // types.
194 #define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
195 A(bool) \
196 A(short) \
197 A(unsigned short) \
198 A(int) \
199 A(unsigned int) \
200 A(long) \
201 A(unsigned long) \
202 A(long long) \
203 A(unsigned long long) \
204 A(double) \
205 A(float) \
206 A(std::string) \
207 A(std::vector<std::string>)
208
209 } // namespace flags_internal
210 ABSL_NAMESPACE_END
211 } // namespace absl
212
213 #endif // ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
214