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_FLAG_H_
17 #define ABSL_FLAGS_INTERNAL_FLAG_H_
18
19 #include <stdint.h>
20
21 #include <atomic>
22 #include <cstring>
23 #include <memory>
24 #include <string>
25 #include <type_traits>
26 #include <typeinfo>
27
28 #include "absl/base/call_once.h"
29 #include "absl/base/config.h"
30 #include "absl/base/thread_annotations.h"
31 #include "absl/flags/config.h"
32 #include "absl/flags/internal/commandlineflag.h"
33 #include "absl/flags/internal/registry.h"
34 #include "absl/memory/memory.h"
35 #include "absl/meta/type_traits.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/string_view.h"
38 #include "absl/synchronization/mutex.h"
39
40 namespace absl {
41 ABSL_NAMESPACE_BEGIN
42 namespace flags_internal {
43
44 ///////////////////////////////////////////////////////////////////////////////
45 // Flag value type operations, eg., parsing, copying, etc. are provided
46 // by function specific to that type with a signature matching FlagOpFn.
47
48 enum class FlagOp {
49 kDelete,
50 kClone,
51 kCopy,
52 kCopyConstruct,
53 kSizeof,
54 kFastTypeId,
55 kRuntimeTypeId,
56 kParse,
57 kUnparse,
58 kValueOffset,
59 };
60 using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
61
62 // Forward declaration for Flag value specific operations.
63 template <typename T>
64 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);
65
66 // Deletes memory interpreting obj as flag value type pointer.
Delete(FlagOpFn op,const void * obj)67 inline void Delete(FlagOpFn op, const void* obj) {
68 op(FlagOp::kDelete, obj, nullptr, nullptr);
69 }
70 // Makes a copy of flag value pointed by obj.
Clone(FlagOpFn op,const void * obj)71 inline void* Clone(FlagOpFn op, const void* obj) {
72 return op(FlagOp::kClone, obj, nullptr, nullptr);
73 }
74 // Copies src to dst interpreting as flag value type pointers.
Copy(FlagOpFn op,const void * src,void * dst)75 inline void Copy(FlagOpFn op, const void* src, void* dst) {
76 op(FlagOp::kCopy, src, dst, nullptr);
77 }
78 // Construct a copy of flag value in a location pointed by dst
79 // based on src - pointer to the flag's value.
CopyConstruct(FlagOpFn op,const void * src,void * dst)80 inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
81 op(FlagOp::kCopyConstruct, src, dst, nullptr);
82 }
83 // Returns true if parsing of input text is successfull.
Parse(FlagOpFn op,absl::string_view text,void * dst,std::string * error)84 inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
85 std::string* error) {
86 return op(FlagOp::kParse, &text, dst, error) != nullptr;
87 }
88 // Returns string representing supplied value.
Unparse(FlagOpFn op,const void * val)89 inline std::string Unparse(FlagOpFn op, const void* val) {
90 std::string result;
91 op(FlagOp::kUnparse, val, &result, nullptr);
92 return result;
93 }
94 // Returns size of flag value type.
Sizeof(FlagOpFn op)95 inline size_t Sizeof(FlagOpFn op) {
96 // This sequence of casts reverses the sequence from
97 // `flags_internal::FlagOps()`
98 return static_cast<size_t>(reinterpret_cast<intptr_t>(
99 op(FlagOp::kSizeof, nullptr, nullptr, nullptr)));
100 }
101 // Returns fast type id coresponding to the value type.
FastTypeId(FlagOpFn op)102 inline FlagFastTypeId FastTypeId(FlagOpFn op) {
103 return reinterpret_cast<FlagFastTypeId>(
104 op(FlagOp::kFastTypeId, nullptr, nullptr, nullptr));
105 }
106 // Returns fast type id coresponding to the value type.
RuntimeTypeId(FlagOpFn op)107 inline const std::type_info* RuntimeTypeId(FlagOpFn op) {
108 return reinterpret_cast<const std::type_info*>(
109 op(FlagOp::kRuntimeTypeId, nullptr, nullptr, nullptr));
110 }
111 // Returns offset of the field value_ from the field impl_ inside of
112 // absl::Flag<T> data. Given FlagImpl pointer p you can get the
113 // location of the corresponding value as:
114 // reinterpret_cast<char*>(p) + ValueOffset().
ValueOffset(FlagOpFn op)115 inline ptrdiff_t ValueOffset(FlagOpFn op) {
116 // This sequence of casts reverses the sequence from
117 // `flags_internal::FlagOps()`
118 return static_cast<ptrdiff_t>(reinterpret_cast<intptr_t>(
119 op(FlagOp::kValueOffset, nullptr, nullptr, nullptr)));
120 }
121
122 // Returns an address of RTTI's typeid(T).
123 template <typename T>
GenRuntimeTypeId()124 inline const std::type_info* GenRuntimeTypeId() {
125 #if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
126 return &typeid(T);
127 #else
128 return nullptr;
129 #endif
130 }
131
132 ///////////////////////////////////////////////////////////////////////////////
133 // Flag help auxiliary structs.
134
135 // This is help argument for absl::Flag encapsulating the string literal pointer
136 // or pointer to function generating it as well as enum descriminating two
137 // cases.
138 using HelpGenFunc = std::string (*)();
139
140 union FlagHelpMsg {
FlagHelpMsg(const char * help_msg)141 constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {}
FlagHelpMsg(HelpGenFunc help_gen)142 constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {}
143
144 const char* literal;
145 HelpGenFunc gen_func;
146 };
147
148 enum class FlagHelpKind : uint8_t { kLiteral = 0, kGenFunc = 1 };
149
150 struct FlagHelpArg {
151 FlagHelpMsg source;
152 FlagHelpKind kind;
153 };
154
155 extern const char kStrippedFlagHelp[];
156
157 // HelpConstexprWrap is used by struct AbslFlagHelpGenFor##name generated by
158 // ABSL_FLAG macro. It is only used to silence the compiler in the case where
159 // help message expression is not constexpr and does not have type const char*.
160 // If help message expression is indeed constexpr const char* HelpConstexprWrap
161 // is just a trivial identity function.
162 template <typename T>
HelpConstexprWrap(const T &)163 const char* HelpConstexprWrap(const T&) {
164 return nullptr;
165 }
HelpConstexprWrap(const char * p)166 constexpr const char* HelpConstexprWrap(const char* p) { return p; }
HelpConstexprWrap(char * p)167 constexpr const char* HelpConstexprWrap(char* p) { return p; }
168
169 // These two HelpArg overloads allows us to select at compile time one of two
170 // way to pass Help argument to absl::Flag. We'll be passing
171 // AbslFlagHelpGenFor##name as T and integer 0 as a single argument to prefer
172 // first overload if possible. If T::Const is evaluatable on constexpr
173 // context (see non template int parameter below) we'll choose first overload.
174 // In this case the help message expression is immediately evaluated and is used
175 // to construct the absl::Flag. No additionl code is generated by ABSL_FLAG.
176 // Otherwise SFINAE kicks in and first overload is dropped from the
177 // consideration, in which case the second overload will be used. The second
178 // overload does not attempt to evaluate the help message expression
179 // immediately and instead delays the evaluation by returing the function
180 // pointer (&T::NonConst) genering the help message when necessary. This is
181 // evaluatable in constexpr context, but the cost is an extra function being
182 // generated in the ABSL_FLAG code.
183 template <typename T, int = (T::Const(), 1)>
HelpArg(int)184 constexpr FlagHelpArg HelpArg(int) {
185 return {FlagHelpMsg(T::Const()), FlagHelpKind::kLiteral};
186 }
187
188 template <typename T>
HelpArg(char)189 constexpr FlagHelpArg HelpArg(char) {
190 return {FlagHelpMsg(&T::NonConst), FlagHelpKind::kGenFunc};
191 }
192
193 ///////////////////////////////////////////////////////////////////////////////
194 // Flag default value auxiliary structs.
195
196 // Signature for the function generating the initial flag value (usually
197 // based on default value supplied in flag's definition)
198 using FlagDfltGenFunc = void* (*)();
199
200 union FlagDefaultSrc {
FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)201 constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
202 : gen_func(gen_func_arg) {}
203
204 void* dynamic_value;
205 FlagDfltGenFunc gen_func;
206 };
207
208 enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 };
209
210 ///////////////////////////////////////////////////////////////////////////////
211 // Flag current value auxiliary structs.
212
UninitializedFlagValue()213 constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; }
214
215 template <typename T>
216 using FlagUseOneWordStorage = std::integral_constant<
217 bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
218 (sizeof(T) <= 8)>;
219
220 #if defined(ABSL_FLAGS_INTERNAL_ATOMIC_DOUBLE_WORD)
221 // Clang does not always produce cmpxchg16b instruction when alignment of a 16
222 // bytes type is not 16.
223 struct alignas(16) AlignedTwoWords {
224 int64_t first;
225 int64_t second;
226
IsInitializedAlignedTwoWords227 bool IsInitialized() const {
228 return first != flags_internal::UninitializedFlagValue();
229 }
230 };
231
232 template <typename T>
233 using FlagUseTwoWordsStorage = std::integral_constant<
234 bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
235 (sizeof(T) > 8) && (sizeof(T) <= 16)>;
236 #else
237 // This is actually unused and only here to avoid ifdefs in other palces.
238 struct AlignedTwoWords {
AlignedTwoWordsAlignedTwoWords239 constexpr AlignedTwoWords() noexcept : dummy() {}
AlignedTwoWordsAlignedTwoWords240 constexpr AlignedTwoWords(int64_t, int64_t) noexcept : dummy() {}
241 char dummy;
242
IsInitializedAlignedTwoWords243 bool IsInitialized() const {
244 std::abort();
245 return true;
246 }
247 };
248
249 // This trait should be type dependent, otherwise SFINAE below will fail
250 template <typename T>
251 using FlagUseTwoWordsStorage =
252 std::integral_constant<bool, sizeof(T) != sizeof(T)>;
253 #endif
254
255 template <typename T>
256 using FlagUseHeapStorage =
257 std::integral_constant<bool, !FlagUseOneWordStorage<T>::value &&
258 !FlagUseTwoWordsStorage<T>::value>;
259
260 enum class FlagValueStorageKind : uint8_t {
261 kHeapAllocated = 0,
262 kOneWordAtomic = 1,
263 kTwoWordsAtomic = 2
264 };
265
266 template <typename T>
StorageKind()267 static constexpr FlagValueStorageKind StorageKind() {
268 return FlagUseHeapStorage<T>::value
269 ? FlagValueStorageKind::kHeapAllocated
270 : FlagUseOneWordStorage<T>::value
271 ? FlagValueStorageKind::kOneWordAtomic
272 : FlagUseTwoWordsStorage<T>::value
273 ? FlagValueStorageKind::kTwoWordsAtomic
274 : FlagValueStorageKind::kHeapAllocated;
275 }
276
277 struct FlagHeapAllocatedValue {
278 using value_type = void*;
279
280 value_type value;
281 };
282
283 struct FlagOneWordValue {
284 using value_type = std::atomic<int64_t>;
FlagOneWordValueFlagOneWordValue285 constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {}
286
287 value_type value;
288 };
289
290 struct FlagTwoWordsValue {
291 using value_type = std::atomic<AlignedTwoWords>;
FlagTwoWordsValueFlagTwoWordsValue292 constexpr FlagTwoWordsValue()
293 : value(AlignedTwoWords{UninitializedFlagValue(), 0}) {}
294
295 value_type value;
296 };
297
298 template <typename T,
299 FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>
300 struct FlagValue;
301
302 template <typename T>
303 struct FlagValue<T, FlagValueStorageKind::kHeapAllocated>
304 : FlagHeapAllocatedValue {
305 bool Get(T*) const { return false; }
306 };
307
308 template <typename T>
309 struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {
310 bool Get(T* dst) const {
311 int64_t one_word_val = value.load(std::memory_order_acquire);
312 if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) {
313 return false;
314 }
315 std::memcpy(dst, static_cast<const void*>(&one_word_val), sizeof(T));
316 return true;
317 }
318 };
319
320 template <typename T>
321 struct FlagValue<T, FlagValueStorageKind::kTwoWordsAtomic> : FlagTwoWordsValue {
322 bool Get(T* dst) const {
323 AlignedTwoWords two_words_val = value.load(std::memory_order_acquire);
324 if (ABSL_PREDICT_FALSE(!two_words_val.IsInitialized())) {
325 return false;
326 }
327 std::memcpy(dst, static_cast<const void*>(&two_words_val), sizeof(T));
328 return true;
329 }
330 };
331
332 ///////////////////////////////////////////////////////////////////////////////
333 // Flag callback auxiliary structs.
334
335 // Signature for the mutation callback used by watched Flags
336 // The callback is noexcept.
337 // TODO(rogeeff): add noexcept after C++17 support is added.
338 using FlagCallbackFunc = void (*)();
339
340 struct FlagCallback {
341 FlagCallbackFunc func;
342 absl::Mutex guard; // Guard for concurrent callback invocations.
343 };
344
345 ///////////////////////////////////////////////////////////////////////////////
346 // Flag implementation, which does not depend on flag value type.
347 // The class encapsulates the Flag's data and access to it.
348
349 struct DynValueDeleter {
350 explicit DynValueDeleter(FlagOpFn op_arg = nullptr) : op(op_arg) {}
351 void operator()(void* ptr) const {
352 if (op != nullptr) flags_internal::Delete(op, ptr);
353 }
354
355 FlagOpFn op;
356 };
357
358 class FlagState;
359
360 class FlagImpl final : public flags_internal::CommandLineFlag {
361 public:
362 constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
363 FlagHelpArg help, FlagValueStorageKind value_kind,
364 FlagDfltGenFunc default_value_gen)
365 : name_(name),
366 filename_(filename),
367 op_(op),
368 help_(help.source),
369 help_source_kind_(static_cast<uint8_t>(help.kind)),
370 value_storage_kind_(static_cast<uint8_t>(value_kind)),
371 def_kind_(static_cast<uint8_t>(FlagDefaultKind::kGenFunc)),
372 modified_(false),
373 on_command_line_(false),
374 counter_(0),
375 callback_(nullptr),
376 default_value_(default_value_gen),
377 data_guard_{} {}
378
379 // Constant access methods
380 void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());
381
382 // Mutating access methods
383 void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());
384
385 // Interfaces to operate on callbacks.
386 void SetCallback(const FlagCallbackFunc mutation_callback)
387 ABSL_LOCKS_EXCLUDED(*DataGuard());
388 void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
389
390 // Used in read/write operations to validate source/target has correct type.
391 // For example if flag is declared as absl::Flag<int> FLAGS_foo, a call to
392 // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed
393 // int. To do that we pass the "assumed" type id (which is deduced from type
394 // int) as an argument `type_id`, which is in turn is validated against the
395 // type id stored in flag object by flag definition statement.
396 void AssertValidType(FlagFastTypeId type_id,
397 const std::type_info* (*gen_rtti)()) const;
398
399 private:
400 template <typename T>
401 friend class Flag;
402 friend class FlagState;
403
404 // Ensures that `data_guard_` is initialized and returns it.
405 absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_);
406 // Returns heap allocated value of type T initialized with default value.
407 std::unique_ptr<void, DynValueDeleter> MakeInitValue() const
408 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
409 // Flag initialization called via absl::call_once.
410 void Init();
411
412 // Offset value access methods. One per storage kind. These methods to not
413 // respect const correctness, so be very carefull using them.
414
415 // This is a shared helper routine which encapsulates most of the magic. Since
416 // it is only used inside the three routines below, which are defined in
417 // flag.cc, we can define it in that file as well.
418 template <typename StorageT>
419 typename StorageT::value_type& OffsetValue() const;
420 // This is an accessor for a value stored in heap allocated storage.
421 // Returns a mutable reference to a pointer to allow vlaue mutation.
422 void*& HeapAllocatedValue() const;
423 // This is an accessor for a value stored as one word atomic. Returns a
424 // mutable reference to an atomic value.
425 std::atomic<int64_t>& OneWordValue() const;
426 // This is an accessor for a value stored as two words atomic. Returns a
427 // mutable reference to an atomic value.
428 std::atomic<AlignedTwoWords>& TwoWordsValue() const;
429
430 // Attempts to parse supplied `value` string. If parsing is successful,
431 // returns new value. Otherwise returns nullptr.
432 std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value,
433 std::string* err) const
434 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
435 // Stores the flag value based on the pointer to the source.
436 void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
437
438 FlagHelpKind HelpSourceKind() const {
439 return static_cast<FlagHelpKind>(help_source_kind_);
440 }
441 FlagValueStorageKind ValueStorageKind() const {
442 return static_cast<FlagValueStorageKind>(value_storage_kind_);
443 }
444 FlagDefaultKind DefaultKind() const
445 ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {
446 return static_cast<FlagDefaultKind>(def_kind_);
447 }
448
449 // CommandLineFlag interface implementation
450 absl::string_view Name() const override;
451 std::string Filename() const override;
452 absl::string_view Typename() const override;
453 std::string Help() const override;
454 FlagFastTypeId TypeId() const override;
455 bool IsModified() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
456 bool IsSpecifiedOnCommandLine() const override
457 ABSL_LOCKS_EXCLUDED(*DataGuard());
458 std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
459 std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
460 bool ValidateInputValue(absl::string_view value) const override
461 ABSL_LOCKS_EXCLUDED(*DataGuard());
462 void CheckDefaultValueParsingRoundtrip() const override
463 ABSL_LOCKS_EXCLUDED(*DataGuard());
464
465 // Interfaces to save and restore flags to/from persistent state.
466 // Returns current flag state or nullptr if flag does not support
467 // saving and restoring a state.
468 std::unique_ptr<FlagStateInterface> SaveState() override
469 ABSL_LOCKS_EXCLUDED(*DataGuard());
470
471 // Restores the flag state to the supplied state object. If there is
472 // nothing to restore returns false. Otherwise returns true.
473 bool RestoreState(const FlagState& flag_state)
474 ABSL_LOCKS_EXCLUDED(*DataGuard());
475
476 bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
477 ValueSource source, std::string* error) override
478 ABSL_LOCKS_EXCLUDED(*DataGuard());
479
480 // Immutable flag's state.
481
482 // Flags name passed to ABSL_FLAG as second arg.
483 const char* const name_;
484 // The file name where ABSL_FLAG resides.
485 const char* const filename_;
486 // Type-specific operations "vtable".
487 const FlagOpFn op_;
488 // Help message literal or function to generate it.
489 const FlagHelpMsg help_;
490 // Indicates if help message was supplied as literal or generator func.
491 const uint8_t help_source_kind_ : 1;
492 // Kind of storage this flag is using for the flag's value.
493 const uint8_t value_storage_kind_ : 2;
494
495 // ------------------------------------------------------------------------
496 // The bytes containing the const bitfields must not be shared with bytes
497 // containing the mutable bitfields.
498 // ------------------------------------------------------------------------
499
500 // Unique tag for absl::call_once call to initialize this flag.
501 //
502 // The placement of this variable between the immutable and mutable bitfields
503 // is important as prevents them from occupying the same byte. If you remove
504 // this variable, make sure to maintain this property.
505 absl::once_flag init_control_;
506
507 // Mutable flag's state (guarded by `data_guard_`).
508
509 // If def_kind_ == kDynamicValue, default_value_ holds a dynamically allocated
510 // value.
511 uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard());
512 // Has this flag's value been modified?
513 bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
514 // Has this flag been specified on command line.
515 bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
516
517 // Mutation counter
518 int64_t counter_ ABSL_GUARDED_BY(*DataGuard());
519 // Optional flag's callback and absl::Mutex to guard the invocations.
520 FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());
521 // Either a pointer to the function generating the default value based on the
522 // value specified in ABSL_FLAG or pointer to the dynamically set default
523 // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish
524 // these two cases.
525 FlagDefaultSrc default_value_;
526
527 // This is reserved space for an absl::Mutex to guard flag data. It will be
528 // initialized in FlagImpl::Init via placement new.
529 // We can't use "absl::Mutex data_guard_", since this class is not literal.
530 // We do not want to use "absl::Mutex* data_guard_", since this would require
531 // heap allocation during initialization, which is both slows program startup
532 // and can fail. Using reserved space + placement new allows us to avoid both
533 // problems.
534 alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)];
535 };
536
537 ///////////////////////////////////////////////////////////////////////////////
538 // The Flag object parameterized by the flag's value type. This class implements
539 // flag reflection handle interface.
540
541 template <typename T>
542 class Flag {
543 public:
544 constexpr Flag(const char* name, const char* filename, const FlagHelpArg help,
545 const FlagDfltGenFunc default_value_gen)
546 : impl_(name, filename, &FlagOps<T>, help,
547 flags_internal::StorageKind<T>(), default_value_gen),
548 value_() {}
549
550 T Get() const {
551 // See implementation notes in CommandLineFlag::Get().
552 union U {
553 T value;
554 U() {}
555 ~U() { value.~T(); }
556 };
557 U u;
558
559 #if !defined(NDEBUG)
560 impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
561 #endif
562
563 if (!value_.Get(&u.value)) impl_.Read(&u.value);
564 return std::move(u.value);
565 }
566 void Set(const T& v) {
567 impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
568 impl_.Write(&v);
569 }
570 void SetCallback(const FlagCallbackFunc mutation_callback) {
571 impl_.SetCallback(mutation_callback);
572 }
573
574 // CommandLineFlag interface
575 absl::string_view Name() const { return impl_.Name(); }
576 std::string Filename() const { return impl_.Filename(); }
577 absl::string_view Typename() const { return ""; }
578 std::string Help() const { return impl_.Help(); }
579 bool IsModified() const { return impl_.IsModified(); }
580 bool IsSpecifiedOnCommandLine() const {
581 return impl_.IsSpecifiedOnCommandLine();
582 }
583 std::string DefaultValue() const { return impl_.DefaultValue(); }
584 std::string CurrentValue() const { return impl_.CurrentValue(); }
585
586 private:
587 template <typename U, bool do_register>
588 friend class FlagRegistrar;
589
590 // Flag's data
591 // The implementation depends on value_ field to be placed exactly after the
592 // impl_ field, so that impl_ can figure out the offset to the value and
593 // access it.
594 FlagImpl impl_;
595 FlagValue<T> value_;
596 };
597
598 ///////////////////////////////////////////////////////////////////////////////
599 // Implementation of Flag value specific operations routine.
600 template <typename T>
601 void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
602 switch (op) {
603 case FlagOp::kDelete:
604 delete static_cast<const T*>(v1);
605 return nullptr;
606 case FlagOp::kClone:
607 return new T(*static_cast<const T*>(v1));
608 case FlagOp::kCopy:
609 *static_cast<T*>(v2) = *static_cast<const T*>(v1);
610 return nullptr;
611 case FlagOp::kCopyConstruct:
612 new (v2) T(*static_cast<const T*>(v1));
613 return nullptr;
614 case FlagOp::kSizeof:
615 return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T)));
616 case FlagOp::kFastTypeId:
617 return const_cast<void*>(base_internal::FastTypeId<T>());
618 case FlagOp::kRuntimeTypeId:
619 return const_cast<std::type_info*>(GenRuntimeTypeId<T>());
620 case FlagOp::kParse: {
621 // Initialize the temporary instance of type T based on current value in
622 // destination (which is going to be flag's default value).
623 T temp(*static_cast<T*>(v2));
624 if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
625 static_cast<std::string*>(v3))) {
626 return nullptr;
627 }
628 *static_cast<T*>(v2) = std::move(temp);
629 return v2;
630 }
631 case FlagOp::kUnparse:
632 *static_cast<std::string*>(v2) =
633 absl::UnparseFlag<T>(*static_cast<const T*>(v1));
634 return nullptr;
635 case FlagOp::kValueOffset: {
636 // Round sizeof(FlagImp) to a multiple of alignof(FlagValue<T>) to get the
637 // offset of the data.
638 ptrdiff_t round_to = alignof(FlagValue<T>);
639 ptrdiff_t offset =
640 (sizeof(FlagImpl) + round_to - 1) / round_to * round_to;
641 return reinterpret_cast<void*>(offset);
642 }
643 }
644 return nullptr;
645 }
646
647 ///////////////////////////////////////////////////////////////////////////////
648 // This class facilitates Flag object registration and tail expression-based
649 // flag definition, for example:
650 // ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
651 template <typename T, bool do_register>
652 class FlagRegistrar {
653 public:
654 explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {
655 if (do_register) flags_internal::RegisterCommandLineFlag(&flag_->impl_);
656 }
657
658 FlagRegistrar& OnUpdate(FlagCallbackFunc cb) && {
659 flag_->SetCallback(cb);
660 return *this;
661 }
662
663 // Make the registrar "die" gracefully as a bool on a line where registration
664 // happens. Registrar objects are intended to live only as temporary.
665 operator bool() const { return true; } // NOLINT
666
667 private:
668 Flag<T>* flag_; // Flag being registered (not owned).
669 };
670
671 // This struct and corresponding overload to MakeDefaultValue are used to
672 // facilitate usage of {} as default value in ABSL_FLAG macro.
673 struct EmptyBraces {};
674
675 template <typename T>
676 T* MakeFromDefaultValue(T t) {
677 return new T(std::move(t));
678 }
679
680 template <typename T>
681 T* MakeFromDefaultValue(EmptyBraces) {
682 return new T{};
683 }
684
685 } // namespace flags_internal
686 ABSL_NAMESPACE_END
687 } // namespace absl
688
689 #endif // ABSL_FLAGS_INTERNAL_FLAG_H_
690