commandlineflag.h
Go to the documentation of this file.
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 <atomic>
20 
21 #include "absl/base/macros.h"
22 #include "absl/flags/marshalling.h"
24 #include "absl/types/optional.h"
25 
26 namespace absl {
27 namespace 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.
31 enum FlagOp {
39 };
40 using FlagOpFn = void* (*)(FlagOp, const void*, void*);
41 using FlagMarshallingOpFn = void* (*)(FlagOp, const void*, void*, void*);
42 
43 // Options that control SetCommandLineOptionWithMode.
45  // update the flag's value unconditionally (can call this multiple times).
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".
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.
54 };
55 
56 // Options that control SetFromString: Source of a value.
58  // Flag is being set by value specified on a command line.
60  // Flag is being set by value specified in the code.
62 };
63 
64 // Signature for the help generation function used as an argument for the
65 // absl::Flag constructor.
66 using 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)
70 using InitialValGenFunc = void* (*)();
71 
72 // Signature for the mutation callback used by watched Flags
73 // The callback is noexcept.
74 // TODO(rogeeff): add noexcept after C++17 support is added.
75 using FlagCallback = void (*)();
76 
77 extern const char kStrippedFlagHelp[];
78 
79 // The per-type function
80 template <typename T>
81 void* FlagOps(FlagOp op, const void* v1, void* v2) {
82  switch (op) {
83  case kDelete:
84  delete static_cast<const T*>(v1);
85  return nullptr;
86  case kClone:
87  return new T(*static_cast<const T*>(v1));
88  case kCopy:
89  *static_cast<T*>(v2) = *static_cast<const T*>(v1);
90  return nullptr;
91  case kCopyConstruct:
92  new (v2) T(*static_cast<const T*>(v1));
93  return nullptr;
94  case kSizeof:
95  return reinterpret_cast<void*>(sizeof(T));
96  default:
97  return nullptr;
98  }
99 }
100 
101 template <typename T>
102 void* FlagMarshallingOps(FlagOp op, const void* v1, void* v2, void* v3) {
103  switch (op) {
104  case kParse: {
105  // initialize the temporary instance of type T based on current value in
106  // destination (which is going to be flag's default value).
107  T temp(*static_cast<T*>(v2));
108  if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
109  static_cast<std::string*>(v3))) {
110  return nullptr;
111  }
112  *static_cast<T*>(v2) = std::move(temp);
113  return v2;
114  }
115  case kUnparse:
116  *static_cast<std::string*>(v2) =
117  absl::UnparseFlag<T>(*static_cast<const T*>(v1));
118  return nullptr;
119  default:
120  return nullptr;
121  }
122 }
123 
124 // Functions that invoke flag-type-specific operations.
125 inline void Delete(FlagOpFn op, const void* obj) {
126  op(flags_internal::kDelete, obj, nullptr);
127 }
128 
129 inline void* Clone(FlagOpFn op, const void* obj) {
130  return op(flags_internal::kClone, obj, nullptr);
131 }
132 
133 inline void Copy(FlagOpFn op, const void* src, void* dst) {
134  op(flags_internal::kCopy, src, dst);
135 }
136 
137 inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
138  op(flags_internal::kCopyConstruct, src, dst);
139 }
140 
141 inline bool Parse(FlagMarshallingOpFn op, absl::string_view text, void* dst,
142  std::string* error) {
143  return op(flags_internal::kParse, &text, dst, error) != nullptr;
144 }
145 
146 inline std::string Unparse(FlagMarshallingOpFn op, const void* val) {
147  std::string result;
148  op(flags_internal::kUnparse, val, &result, nullptr);
149  return result;
150 }
151 
152 inline size_t Sizeof(FlagOpFn op) {
153  // This sequence of casts reverses the sequence from base::internal::FlagOps()
154  return static_cast<size_t>(reinterpret_cast<intptr_t>(
155  op(flags_internal::kSizeof, nullptr, nullptr)));
156 }
157 
158 // The following struct contains the locks in a CommandLineFlag struct.
159 // They are in a separate struct that is lazily allocated to avoid problems
160 // with static initialization and to avoid multiple allocations.
162  absl::Mutex primary_mu; // protects several fields in CommandLineFlag
163  absl::Mutex callback_mu; // used to serialize callbacks
164 };
165 
166 // Holds either a pointer to help text or a function which produces it. This is
167 // needed for supporting both static initialization of Flags while supporting
168 // the legacy registration framework. We can't use absl::variant<const char*,
169 // const char*(*)()> since anybody passing 0 or nullptr in to a CommandLineFlag
170 // would find an ambiguity.
171 class HelpText {
172  public:
173  static constexpr HelpText FromFunctionPointer(const HelpGenFunc fn) {
174  return HelpText(fn, nullptr);
175  }
176  static constexpr HelpText FromStaticCString(const char* msg) {
177  return HelpText(nullptr, msg);
178  }
179 
180  std::string GetHelpText() const;
181 
182  HelpText() = delete;
183  HelpText(const HelpText&) = default;
184  HelpText(HelpText&&) = default;
185 
186  private:
187  explicit constexpr HelpText(const HelpGenFunc fn, const char* msg)
188  : help_function_(fn), help_message_(msg) {}
189 
191  const char* help_message_;
192 };
193 
194 // Holds all information for a flag.
196  constexpr CommandLineFlag(
197  const char* name_arg, HelpText help_text, const char* filename_arg,
198  const flags_internal::FlagOpFn op_arg,
199  const flags_internal::FlagMarshallingOpFn marshalling_op_arg,
200  const flags_internal::InitialValGenFunc initial_value_gen,
201  const bool retired_arg, void* def_arg, void* cur_arg)
202  : name(name_arg),
203  help(help_text),
204  filename(filename_arg),
205  op(op_arg),
206  marshalling_op(marshalling_op_arg),
207  make_init_value(initial_value_gen),
208  retired(retired_arg),
209  inited(false),
210  modified(false),
211  on_command_line(false),
212  validator(nullptr),
213  callback(nullptr),
214  def(def_arg),
215  cur(cur_arg),
216  counter(0),
217  atomic(kAtomicInit),
218  locks(nullptr) {}
219 
220  // Not copyable/assignable.
221  CommandLineFlag(const CommandLineFlag&) = delete;
222  CommandLineFlag& operator=(const CommandLineFlag&) = delete;
223 
224  absl::string_view Name() const { return name; }
225  std::string Help() const { return help.GetHelpText(); }
226  bool IsRetired() const { return this->retired; }
227  bool IsSpecifiedOnCommandLine() const { return on_command_line; }
228  // Returns true iff this is a handle to an Abseil Flag.
229  bool IsAbseilFlag() const {
230  // Set to null for V1 flags
231  return this->make_init_value != nullptr;
232  }
233 
234  absl::string_view Typename() const;
235  std::string Filename() const;
236  std::string DefaultValue() const;
237  std::string CurrentValue() const;
238 
239  // Return true iff flag has type T.
240  template <typename T>
241  inline bool IsOfType() const {
242  return this->op == &flags_internal::FlagOps<T>;
243  }
244 
245  // Attempts to retrieve the flag value. Returns value on success,
246  // absl::nullopt otherwise.
247  template <typename T>
249  if (IsRetired() || flags_internal::FlagOps<T> != this->op)
250  return absl::nullopt;
251 
252  T res;
253  Read(&res, flags_internal::FlagOps<T>);
254 
255  return res;
256  }
257 
258  void SetCallback(const flags_internal::FlagCallback mutation_callback);
259 
260  // Sets the value of the flag based on specified std::string `value`. If the flag
261  // was successfully set to new value, it returns true. Otherwise, sets `error`
262  // to indicate the error, leaves the flag unchanged, and returns false. There
263  // are three ways to set the flag's value:
264  // * Update the current flag value
265  // * Update the flag's default value
266  // * Update the current flag value if it was never set before
267  // The mode is selected based on `set_mode` parameter.
268  bool SetFromString(absl::string_view value,
270  flags_internal::ValueSource source, std::string* error);
271 
272  // Constant configuration for a particular flag.
273  private:
274  const char* const name;
275  const HelpText help;
276  const char* const filename;
277 
278  public:
279  const FlagOpFn op; // Type-specific handler
280  const FlagMarshallingOpFn marshalling_op; // Marshalling ops handler
281  const InitialValGenFunc make_init_value; // Makes initial value for the flag
282  const bool retired; // Is the flag retired?
283  std::atomic<bool> inited; // fields have been lazily initialized
284 
285  // Mutable state (guarded by locks->primary_mu).
286  bool modified; // Has flag value been modified?
287  bool on_command_line; // Specified on command line.
288  bool (*validator)(); // Validator function, or nullptr
289  FlagCallback callback; // Mutation callback, or nullptr
290  void* def; // Lazily initialized pointer to default value
291  void* cur; // Lazily initialized pointer to current value
292  int64_t counter; // Mutation counter
293 
294  // For some types, a copy of the current value is kept in an atomically
295  // accessible field.
296  static const int64_t kAtomicInit = 0xababababababababll;
297  std::atomic<int64_t> atomic;
298 
299  // Lazily initialized mutexes for this flag value. We cannot inline a
300  // SpinLock or Mutex here because those have non-constexpr constructors and
301  // so would prevent constant initialization of this type.
302  // TODO(rogeeff): fix it once Mutex has constexpr constructor
303  struct CommandLineFlagLocks* locks; // locks, laziliy allocated.
304 
305  // copy construct new value of flag's type in a memory referenced by dst
306  // based on current flag's value
307  void Read(void* dst, const flags_internal::FlagOpFn dst_op) const;
308  // updates flag's value to *src (locked)
309  void Write(const void* src, const flags_internal::FlagOpFn src_op);
310 
312  "temporary until FlagName call sites are migrated and validator API is "
313  "changed")
314  const char* NameAsCString() const { return name; }
315 
316  private:
317  friend class FlagRegistry;
318 };
319 
320 // Ensure that the lazily initialized fields of *flag have been initialized,
321 // and return &flag->locks->primary_mu.
323 // Update any copy of the flag value that is stored in an atomic word.
324 // In addition if flag has a mutation callback this function invokes it. While
325 // callback is being invoked the primary flag's mutex is unlocked and it is
326 // re-locked back after call to callback is completed. Callback invocation is
327 // guarded by flag's secondary mutex instead which prevents concurrent callback
328 // invocation. Note that it is possible for other thread to grab the primary
329 // lock and update flag's value at any time during the callback invocation.
330 // This is by design. Callback can get a value of the flag if necessary, but it
331 // might be different from the value initiated the callback and it also can be
332 // different by the time the callback invocation is completed.
333 // Requires that *primary_lock be held in exclusive mode; it may be released
334 // and reacquired by the implementation.
335 void UpdateCopy(CommandLineFlag* flag, absl::Mutex* primary_lock);
336 // Return true iff flag value was changed via direct-access.
337 bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b);
338 // Direct-access flags can be modified without going through the
339 // flag API. Detect such changes and updated the modified bit.
341 // Invoke the flag validators for old flags.
342 // TODO(rogeeff): implement proper validators for Abseil Flags
343 bool Validate(CommandLineFlag* flag, const void* value);
344 
345 // This macro is the "source of truth" for the list of supported flag types we
346 // expect to perform lock free operations on. Specifically it generates code,
347 // a one argument macro operating on a type, supplied as a macro argument, for
348 // each type in the list.
349 #define ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(A) \
350  A(bool) \
351  A(short) \
352  A(unsigned short) \
353  A(int) \
354  A(unsigned int) \
355  A(long) \
356  A(unsigned long) \
357  A(long long) \
358  A(unsigned long long) \
359  A(double) \
360  A(float)
361 
362 } // namespace flags_internal
363 } // namespace absl
364 
365 #endif // ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
void Delete(FlagOpFn op, const void *obj)
std::string(*)() HelpGenFunc
static constexpr HelpText FromStaticCString(const char *msg)
bool Parse(FlagMarshallingOpFn op, absl::string_view text, void *dst, std::string *error)
struct CommandLineFlagLocks * locks
void UpdateModifiedBit(CommandLineFlag *flag)
const InitialValGenFunc make_init_value
bool Validate(CommandLineFlag *, const void *)
static constexpr HelpText FromFunctionPointer(const HelpGenFunc fn)
void * Clone(FlagOpFn op, const void *obj)
size_t Sizeof(FlagOpFn op)
void *(*)(FlagOp, const void *, void *) FlagOpFn
void CopyConstruct(FlagOpFn op, const void *src, void *dst)
ABSL_DEPRECATED("temporary until FlagName call sites are migrated and validator API is " "changed") const char *NameAsCString() const
int * counter
Definition: algorithm.h:29
void *(*)(FlagOp, const void *, void *, void *) FlagMarshallingOpFn
constexpr CommandLineFlag(const char *name_arg, HelpText help_text, const char *filename_arg, const flags_internal::FlagOpFn op_arg, const flags_internal::FlagMarshallingOpFn marshalling_op_arg, const flags_internal::InitialValGenFunc initial_value_gen, const bool retired_arg, void *def_arg, void *cur_arg)
size_t value
void Copy(FlagOpFn op, const void *src, void *dst)
const char kStrippedFlagHelp[]
char name[1]
Definition: mutex.cc:296
const char * msg
Definition: mutex.cc:254
std::string Unparse(FlagMarshallingOpFn op, const void *val)
constexpr HelpText(const HelpGenFunc fn, const char *msg)
void *(*)() InitialValGenFunc
uint64_t b
Definition: layout_test.cc:50
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: utility.h:219
void UpdateCopy(CommandLineFlag *flag, absl::Mutex *primary_lock) EXCLUSIVE_LOCKS_REQUIRED(primary_lock)
const FlagMarshallingOpFn marshalling_op
absl::Mutex * InitFlagIfNecessary(CommandLineFlag *flag) LOCK_RETURNED(flag -> locks->primary_mu)
void * FlagOps(FlagOp op, const void *v1, void *v2)
void * FlagMarshallingOps(FlagOp op, const void *v1, void *v2, void *v3)
bool ChangedDirectly(CommandLineFlag *flag, const void *a, const void *b)


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:18