blob: 284286b6be1802df49a7ade5e183c9f038901951 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001//
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 <atomic>
20
21#include "absl/base/macros.h"
22#include "absl/flags/marshalling.h"
23#include "absl/synchronization/mutex.h"
24#include "absl/types/optional.h"
25
26namespace absl {
27namespace flags_internal {
28
29// Type-specific operations, eg., parsing, copying, etc. are provided
30// by function specific to that type with a signature matching FlagOpFn.
31enum FlagOp {
32 kDelete,
33 kClone,
34 kCopy,
35 kCopyConstruct,
36 kSizeof,
37 kParse,
38 kUnparse
39};
40using FlagOpFn = void* (*)(FlagOp, const void*, void*);
41using FlagMarshallingOpFn = void* (*)(FlagOp, const void*, void*, void*);
42
43// Options that control SetCommandLineOptionWithMode.
44enum FlagSettingMode {
45 // update the flag's value unconditionally (can call this multiple times).
46 SET_FLAGS_VALUE,
47 // update the flag's value, but *only if* it has not yet been updated
48 // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef".
49 SET_FLAG_IF_DEFAULT,
50 // set the flag's default value to this. If the flag has not been updated
51 // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef")
52 // change the flag's current value to the new default value as well.
53 SET_FLAGS_DEFAULT
54};
55
56// Options that control SetFromString: Source of a value.
57enum ValueSource {
58 // Flag is being set by value specified on a command line.
59 kCommandLine,
60 // Flag is being set by value specified in the code.
61 kProgrammaticChange,
62};
63
64// Signature for the help generation function used as an argument for the
65// absl::Flag constructor.
66using HelpGenFunc = std::string (*)();
67
68// Signature for the function generating the initial flag value based (usually
69// based on default value supplied in flag's definition)
70using InitialValGenFunc = void* (*)();
71
72extern const char kStrippedFlagHelp[];
73
74// The per-type function
75template <typename T>
76void* FlagOps(FlagOp op, const void* v1, void* v2) {
77 switch (op) {
78 case kDelete:
79 delete static_cast<const T*>(v1);
80 return nullptr;
81 case kClone:
82 return new T(*static_cast<const T*>(v1));
83 case kCopy:
84 *static_cast<T*>(v2) = *static_cast<const T*>(v1);
85 return nullptr;
86 case kCopyConstruct:
87 new (v2) T(*static_cast<const T*>(v1));
88 return nullptr;
89 case kSizeof:
90 return reinterpret_cast<void*>(sizeof(T));
91 default:
92 return nullptr;
93 }
94}
95
96template <typename T>
97void* FlagMarshallingOps(FlagOp op, const void* v1, void* v2, void* v3) {
98 switch (op) {
99 case kParse: {
100 // initialize the temporary instance of type T based on current value in
101 // destination (which is going to be flag's default value).
102 T temp(*static_cast<T*>(v2));
103 if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
104 static_cast<std::string*>(v3))) {
105 return nullptr;
106 }
107 *static_cast<T*>(v2) = std::move(temp);
108 return v2;
109 }
110 case kUnparse:
111 *static_cast<std::string*>(v2) =
112 absl::UnparseFlag<T>(*static_cast<const T*>(v1));
113 return nullptr;
114 default:
115 return nullptr;
116 }
117}
118
119// Functions that invoke flag-type-specific operations.
120inline void Delete(FlagOpFn op, const void* obj) {
121 op(flags_internal::kDelete, obj, nullptr);
122}
123
124inline void* Clone(FlagOpFn op, const void* obj) {
125 return op(flags_internal::kClone, obj, nullptr);
126}
127
128inline void Copy(FlagOpFn op, const void* src, void* dst) {
129 op(flags_internal::kCopy, src, dst);
130}
131
132inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
133 op(flags_internal::kCopyConstruct, src, dst);
134}
135
136inline bool Parse(FlagMarshallingOpFn op, absl::string_view text, void* dst,
137 std::string* error) {
138 return op(flags_internal::kParse, &text, dst, error) != nullptr;
139}
140
141inline std::string Unparse(FlagMarshallingOpFn op, const void* val) {
142 std::string result;
143 op(flags_internal::kUnparse, val, &result, nullptr);
144 return result;
145}
146
147inline size_t Sizeof(FlagOpFn op) {
148 // This sequence of casts reverses the sequence from base::internal::FlagOps()
149 return static_cast<size_t>(reinterpret_cast<intptr_t>(
150 op(flags_internal::kSizeof, nullptr, nullptr)));
151}
152
153// The following struct contains the locks in a CommandLineFlag struct.
154// They are in a separate struct that is lazily allocated to avoid problems
155// with static initialization and to avoid multiple allocations.
156struct CommandLineFlagLocks {
157 absl::Mutex primary_mu; // protects several fields in CommandLineFlag
158 absl::Mutex callback_mu; // used to serialize callbacks
159};
160
161// Holds either a pointer to help text or a function which produces it. This is
162// needed for supporting both static initialization of Flags while supporting
163// the legacy registration framework. We can't use absl::variant<const char*,
164// const char*(*)()> since anybody passing 0 or nullptr in to a CommandLineFlag
165// would find an ambiguity.
166class HelpText {
167 public:
168 static constexpr HelpText FromFunctionPointer(const HelpGenFunc fn) {
169 return HelpText(fn, nullptr);
170 }
171 static constexpr HelpText FromStaticCString(const char* msg) {
172 return HelpText(nullptr, msg);
173 }
174
175 std::string GetHelpText() const;
176
177 HelpText() = delete;
178 HelpText(const HelpText&) = default;
179 HelpText(HelpText&&) = default;
180
181 private:
182 explicit constexpr HelpText(const HelpGenFunc fn, const char* msg)
183 : help_function_(fn), help_message_(msg) {}
184
185 HelpGenFunc help_function_;
186 const char* help_message_;
187};
188
189// Holds all information for a flag.
190class CommandLineFlag {
191 public:
192 constexpr CommandLineFlag(
193 const char* name, HelpText help_text, const char* filename,
194 const flags_internal::FlagOpFn op,
195 const flags_internal::FlagMarshallingOpFn marshalling_op,
196 const flags_internal::InitialValGenFunc initial_value_gen, void* def,
197 void* cur)
198 : name_(name),
199 help_(help_text),
200 filename_(filename),
201 op_(op),
202 marshalling_op_(marshalling_op),
203 make_init_value_(initial_value_gen),
204 inited_(false),
205 modified_(false),
206 on_command_line_(false),
207 def_(def),
208 cur_(cur),
209 counter_(0),
210 locks_(nullptr) {}
211
212 // Virtual destructor
213 virtual void Destroy() const = 0;
214
215 // Not copyable/assignable.
216 CommandLineFlag(const CommandLineFlag&) = delete;
217 CommandLineFlag& operator=(const CommandLineFlag&) = delete;
218
219 // Access methods.
220
221 // Returns true iff this object corresponds to retired flag
222 virtual bool IsRetired() const { return false; }
223 // Returns true iff this is a handle to an Abseil Flag.
224 virtual bool IsAbseilFlag() const { return true; }
225
226 absl::string_view Name() const { return name_; }
227 std::string Help() const { return help_.GetHelpText(); }
228 bool IsModified() const;
229 void SetModified(bool is_modified);
230 bool IsSpecifiedOnCommandLine() const;
231
232 absl::string_view Typename() const;
233 std::string Filename() const;
234 std::string DefaultValue() const;
235 std::string CurrentValue() const;
236
237 // Interface to store the value in atomic if one used. This is short term
238 // interface. To be reworked once cur_ is moved.
239 virtual void StoreAtomic() {}
240
241 // Interfaces to operate on validators.
242 virtual bool HasValidatorFn() const { return false; }
243 virtual bool InvokeValidator(const void* /*value*/) const { return true; }
244 // Invoke the flag validators for old flags.
245 // TODO(rogeeff): implement proper validators for Abseil Flags
246 bool ValidateDefaultValue() const;
247 bool ValidateInputValue(absl::string_view value) const;
248
249 // Return true iff flag has type T.
250 template <typename T>
251 inline bool IsOfType() const {
252 return op_ == &flags_internal::FlagOps<T>;
253 }
254
255 // Attempts to retrieve the flag value. Returns value on success,
256 // absl::nullopt otherwise.
257 template <typename T>
258 absl::optional<T> Get() const {
259 if (IsRetired() || flags_internal::FlagOps<T> != op_) return absl::nullopt;
260
261 T res;
262 Read(&res, flags_internal::FlagOps<T>);
263
264 return res;
265 }
266
267 // Interfaces to overate on callbacks.
268 virtual void InvokeCallback() {}
269
270 // Sets the value of the flag based on specified std::string `value`. If the flag
271 // was successfully set to new value, it returns true. Otherwise, sets `error`
272 // to indicate the error, leaves the flag unchanged, and returns false. There
273 // are three ways to set the flag's value:
274 // * Update the current flag value
275 // * Update the flag's default value
276 // * Update the current flag value if it was never set before
277 // The mode is selected based on `set_mode` parameter.
278 bool SetFromString(absl::string_view value,
279 flags_internal::FlagSettingMode set_mode,
280 flags_internal::ValueSource source, std::string* error);
281
282 void CheckDefaultValueParsingRoundtrip() const;
283
284 // Constant configuration for a particular flag.
285 protected:
286 ~CommandLineFlag() = default;
287
288 const char* const name_;
289 const HelpText help_;
290 const char* const filename_;
291
292 const FlagOpFn op_; // Type-specific handler
293 const FlagMarshallingOpFn marshalling_op_; // Marshalling ops handler
294 const InitialValGenFunc make_init_value_; // Makes initial value for the flag
295 std::atomic<bool> inited_; // fields have been lazily initialized
296
297 // Mutable state (guarded by locks_->primary_mu).
298 bool modified_; // Has flag value been modified?
299 bool on_command_line_; // Specified on command line.
300 void* def_; // Lazily initialized pointer to default value
301 void* cur_; // Lazily initialized pointer to current value
302 int64_t counter_; // Mutation counter
303
304 // Lazily initialized mutexes for this flag value. We cannot inline a
305 // SpinLock or Mutex here because those have non-constexpr constructors and
306 // so would prevent constant initialization of this type.
307 // TODO(rogeeff): fix it once Mutex has constexpr constructor
308 struct CommandLineFlagLocks* locks_; // locks, laziliy allocated.
309
310 // Ensure that the lazily initialized fields of *flag have been initialized,
311 // and return the lock which should be locked when flag's state is mutated.
312 absl::Mutex* InitFlagIfNecessary() const ABSL_LOCK_RETURNED(locks_->primary_mu);
313
314 // copy construct new value of flag's type in a memory referenced by dst
315 // based on current flag's value
316 void Read(void* dst, const flags_internal::FlagOpFn dst_op) const;
317 // updates flag's value to *src (locked)
318 void Write(const void* src, const flags_internal::FlagOpFn src_op);
319
320 friend class FlagRegistry;
321 friend class FlagPtrMap;
322 friend class FlagSaverImpl;
323 friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
324 absl::string_view value, std::string* err);
325 friend absl::Mutex* InitFlag(CommandLineFlag* flag);
326
327 // This is a short term, until we completely rework persistent state
328 // storage API.
329 virtual void* GetValidator() const { return nullptr; }
330 virtual bool SetValidator(void*) { return false; }
331};
332
333// Update any copy of the flag value that is stored in an atomic word.
334// In addition if flag has a mutation callback this function invokes it. While
335// callback is being invoked the primary flag's mutex is unlocked and it is
336// re-locked back after call to callback is completed. Callback invocation is
337// guarded by flag's secondary mutex instead which prevents concurrent callback
338// invocation. Note that it is possible for other thread to grab the primary
339// lock and update flag's value at any time during the callback invocation.
340// This is by design. Callback can get a value of the flag if necessary, but it
341// might be different from the value initiated the callback and it also can be
342// different by the time the callback invocation is completed.
343// Requires that *primary_lock be held in exclusive mode; it may be released
344// and reacquired by the implementation.
345void UpdateCopy(CommandLineFlag* flag);
346// Return true iff flag value was changed via direct-access.
347bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b);
348
349// This macro is the "source of truth" for the list of supported flag types we
350// expect to perform lock free operations on. Specifically it generates code,
351// a one argument macro operating on a type, supplied as a macro argument, for
352// each type in the list.
353#define ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(A) \
354 A(bool) \
355 A(short) \
356 A(unsigned short) \
357 A(int) \
358 A(unsigned int) \
359 A(long) \
360 A(unsigned long) \
361 A(long long) \
362 A(unsigned long long) \
363 A(double) \
364 A(float)
365
366} // namespace flags_internal
367} // namespace absl
368
369#endif // ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_