flag.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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. #include "absl/flags/internal/flag.h"
  16. #include <assert.h>
  17. #include <stddef.h>
  18. #include <stdint.h>
  19. #include <string.h>
  20. #include <array>
  21. #include <atomic>
  22. #include <memory>
  23. #include <new>
  24. #include <string>
  25. #include <typeinfo>
  26. #include "absl/base/call_once.h"
  27. #include "absl/base/casts.h"
  28. #include "absl/base/config.h"
  29. #include "absl/base/optimization.h"
  30. #include "absl/flags/config.h"
  31. #include "absl/flags/internal/commandlineflag.h"
  32. #include "absl/flags/usage_config.h"
  33. #include "absl/memory/memory.h"
  34. #include "absl/strings/str_cat.h"
  35. #include "absl/strings/string_view.h"
  36. #include "absl/synchronization/mutex.h"
  37. namespace absl {
  38. ABSL_NAMESPACE_BEGIN
  39. namespace flags_internal {
  40. // The help message indicating that the commandline flag has been
  41. // 'stripped'. It will not show up when doing "-help" and its
  42. // variants. The flag is stripped if ABSL_FLAGS_STRIP_HELP is set to 1
  43. // before including absl/flags/flag.h
  44. const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
  45. namespace {
  46. // Currently we only validate flag values for user-defined flag types.
  47. bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) {
  48. #define DONT_VALIDATE(T, _) \
  49. if (flag_type_id == base_internal::FastTypeId<T>()) return false;
  50. ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(DONT_VALIDATE)
  51. #undef DONT_VALIDATE
  52. return true;
  53. }
  54. // RAII helper used to temporarily unlock and relock `absl::Mutex`.
  55. // This is used when we need to ensure that locks are released while
  56. // invoking user supplied callbacks and then reacquired, since callbacks may
  57. // need to acquire these locks themselves.
  58. class MutexRelock {
  59. public:
  60. explicit MutexRelock(absl::Mutex& mu) : mu_(mu) { mu_.Unlock(); }
  61. ~MutexRelock() { mu_.Lock(); }
  62. MutexRelock(const MutexRelock&) = delete;
  63. MutexRelock& operator=(const MutexRelock&) = delete;
  64. private:
  65. absl::Mutex& mu_;
  66. };
  67. } // namespace
  68. ///////////////////////////////////////////////////////////////////////////////
  69. // Persistent state of the flag data.
  70. class FlagImpl;
  71. class FlagState : public flags_internal::FlagStateInterface {
  72. public:
  73. template <typename V>
  74. FlagState(FlagImpl& flag_impl, const V& v, bool modified,
  75. bool on_command_line, int64_t counter)
  76. : flag_impl_(flag_impl),
  77. value_(v),
  78. modified_(modified),
  79. on_command_line_(on_command_line),
  80. counter_(counter) {}
  81. ~FlagState() override {
  82. if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer &&
  83. flag_impl_.ValueStorageKind() != FlagValueStorageKind::kSequenceLocked)
  84. return;
  85. flags_internal::Delete(flag_impl_.op_, value_.heap_allocated);
  86. }
  87. private:
  88. friend class FlagImpl;
  89. // Restores the flag to the saved state.
  90. void Restore() const override {
  91. if (!flag_impl_.RestoreState(*this)) return;
  92. ABSL_INTERNAL_LOG(INFO,
  93. absl::StrCat("Restore saved value of ", flag_impl_.Name(),
  94. " to: ", flag_impl_.CurrentValue()));
  95. }
  96. // Flag and saved flag data.
  97. FlagImpl& flag_impl_;
  98. union SavedValue {
  99. explicit SavedValue(void* v) : heap_allocated(v) {}
  100. explicit SavedValue(int64_t v) : one_word(v) {}
  101. void* heap_allocated;
  102. int64_t one_word;
  103. } value_;
  104. bool modified_;
  105. bool on_command_line_;
  106. int64_t counter_;
  107. };
  108. ///////////////////////////////////////////////////////////////////////////////
  109. // Flag implementation, which does not depend on flag value type.
  110. DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {}
  111. void DynValueDeleter::operator()(void* ptr) const {
  112. if (op == nullptr) return;
  113. Delete(op, ptr);
  114. }
  115. void FlagImpl::Init() {
  116. new (&data_guard_) absl::Mutex;
  117. auto def_kind = static_cast<FlagDefaultKind>(def_kind_);
  118. switch (ValueStorageKind()) {
  119. case FlagValueStorageKind::kValueAndInitBit:
  120. case FlagValueStorageKind::kOneWordAtomic: {
  121. alignas(int64_t) std::array<char, sizeof(int64_t)> buf{};
  122. if (def_kind == FlagDefaultKind::kGenFunc) {
  123. (*default_value_.gen_func)(buf.data());
  124. } else {
  125. assert(def_kind != FlagDefaultKind::kDynamicValue);
  126. std::memcpy(buf.data(), &default_value_, Sizeof(op_));
  127. }
  128. if (ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit) {
  129. // We presume here the memory layout of FlagValueAndInitBit struct.
  130. uint8_t initialized = 1;
  131. std::memcpy(buf.data() + Sizeof(op_), &initialized,
  132. sizeof(initialized));
  133. }
  134. OneWordValue().store(absl::bit_cast<int64_t>(buf),
  135. std::memory_order_release);
  136. break;
  137. }
  138. case FlagValueStorageKind::kSequenceLocked: {
  139. // For this storage kind the default_value_ always points to gen_func
  140. // during initialization.
  141. assert(def_kind == FlagDefaultKind::kGenFunc);
  142. (*default_value_.gen_func)(AtomicBufferValue());
  143. break;
  144. }
  145. case FlagValueStorageKind::kAlignedBuffer:
  146. // For this storage kind the default_value_ always points to gen_func
  147. // during initialization.
  148. assert(def_kind == FlagDefaultKind::kGenFunc);
  149. (*default_value_.gen_func)(AlignedBufferValue());
  150. break;
  151. }
  152. seq_lock_.MarkInitialized();
  153. }
  154. absl::Mutex* FlagImpl::DataGuard() const {
  155. absl::call_once(const_cast<FlagImpl*>(this)->init_control_, &FlagImpl::Init,
  156. const_cast<FlagImpl*>(this));
  157. // data_guard_ is initialized inside Init.
  158. return reinterpret_cast<absl::Mutex*>(&data_guard_);
  159. }
  160. void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id,
  161. const std::type_info* (*gen_rtti)()) const {
  162. FlagFastTypeId lhs_type_id = flags_internal::FastTypeId(op_);
  163. // `rhs_type_id` is the fast type id corresponding to the declaration
  164. // visibile at the call site. `lhs_type_id` is the fast type id
  165. // corresponding to the type specified in flag definition. They must match
  166. // for this operation to be well-defined.
  167. if (ABSL_PREDICT_TRUE(lhs_type_id == rhs_type_id)) return;
  168. const std::type_info* lhs_runtime_type_id =
  169. flags_internal::RuntimeTypeId(op_);
  170. const std::type_info* rhs_runtime_type_id = (*gen_rtti)();
  171. if (lhs_runtime_type_id == rhs_runtime_type_id) return;
  172. #if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
  173. if (*lhs_runtime_type_id == *rhs_runtime_type_id) return;
  174. #endif
  175. ABSL_INTERNAL_LOG(
  176. FATAL, absl::StrCat("Flag '", Name(),
  177. "' is defined as one type and declared as another"));
  178. }
  179. std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
  180. void* res = nullptr;
  181. switch (DefaultKind()) {
  182. case FlagDefaultKind::kDynamicValue:
  183. res = flags_internal::Clone(op_, default_value_.dynamic_value);
  184. break;
  185. case FlagDefaultKind::kGenFunc:
  186. res = flags_internal::Alloc(op_);
  187. (*default_value_.gen_func)(res);
  188. break;
  189. default:
  190. res = flags_internal::Clone(op_, &default_value_);
  191. break;
  192. }
  193. return {res, DynValueDeleter{op_}};
  194. }
  195. void FlagImpl::StoreValue(const void* src) {
  196. switch (ValueStorageKind()) {
  197. case FlagValueStorageKind::kValueAndInitBit:
  198. case FlagValueStorageKind::kOneWordAtomic: {
  199. // Load the current value to avoid setting 'init' bit manualy.
  200. int64_t one_word_val = OneWordValue().load(std::memory_order_acquire);
  201. std::memcpy(&one_word_val, src, Sizeof(op_));
  202. OneWordValue().store(one_word_val, std::memory_order_release);
  203. seq_lock_.IncrementModificationCount();
  204. break;
  205. }
  206. case FlagValueStorageKind::kSequenceLocked: {
  207. seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_));
  208. break;
  209. }
  210. case FlagValueStorageKind::kAlignedBuffer:
  211. Copy(op_, src, AlignedBufferValue());
  212. seq_lock_.IncrementModificationCount();
  213. break;
  214. }
  215. modified_ = true;
  216. InvokeCallback();
  217. }
  218. absl::string_view FlagImpl::Name() const { return name_; }
  219. std::string FlagImpl::Filename() const {
  220. return flags_internal::GetUsageConfig().normalize_filename(filename_);
  221. }
  222. std::string FlagImpl::Help() const {
  223. return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
  224. : help_.gen_func();
  225. }
  226. FlagFastTypeId FlagImpl::TypeId() const {
  227. return flags_internal::FastTypeId(op_);
  228. }
  229. int64_t FlagImpl::ModificationCount() const {
  230. return seq_lock_.ModificationCount();
  231. }
  232. bool FlagImpl::IsSpecifiedOnCommandLine() const {
  233. absl::MutexLock l(DataGuard());
  234. return on_command_line_;
  235. }
  236. std::string FlagImpl::DefaultValue() const {
  237. absl::MutexLock l(DataGuard());
  238. auto obj = MakeInitValue();
  239. return flags_internal::Unparse(op_, obj.get());
  240. }
  241. std::string FlagImpl::CurrentValue() const {
  242. auto* guard = DataGuard(); // Make sure flag initialized
  243. switch (ValueStorageKind()) {
  244. case FlagValueStorageKind::kValueAndInitBit:
  245. case FlagValueStorageKind::kOneWordAtomic: {
  246. const auto one_word_val =
  247. absl::bit_cast<std::array<char, sizeof(int64_t)>>(
  248. OneWordValue().load(std::memory_order_acquire));
  249. return flags_internal::Unparse(op_, one_word_val.data());
  250. }
  251. case FlagValueStorageKind::kSequenceLocked: {
  252. std::unique_ptr<void, DynValueDeleter> cloned(flags_internal::Alloc(op_),
  253. DynValueDeleter{op_});
  254. ReadSequenceLockedData(cloned.get());
  255. return flags_internal::Unparse(op_, cloned.get());
  256. }
  257. case FlagValueStorageKind::kAlignedBuffer: {
  258. absl::MutexLock l(guard);
  259. return flags_internal::Unparse(op_, AlignedBufferValue());
  260. }
  261. }
  262. return "";
  263. }
  264. void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) {
  265. absl::MutexLock l(DataGuard());
  266. if (callback_ == nullptr) {
  267. callback_ = new FlagCallback;
  268. }
  269. callback_->func = mutation_callback;
  270. InvokeCallback();
  271. }
  272. void FlagImpl::InvokeCallback() const {
  273. if (!callback_) return;
  274. // Make a copy of the C-style function pointer that we are about to invoke
  275. // before we release the lock guarding it.
  276. FlagCallbackFunc cb = callback_->func;
  277. // If the flag has a mutation callback this function invokes it. While the
  278. // callback is being invoked the primary flag's mutex is unlocked and it is
  279. // re-locked back after call to callback is completed. Callback invocation is
  280. // guarded by flag's secondary mutex instead which prevents concurrent
  281. // callback invocation. Note that it is possible for other thread to grab the
  282. // primary lock and update flag's value at any time during the callback
  283. // invocation. This is by design. Callback can get a value of the flag if
  284. // necessary, but it might be different from the value initiated the callback
  285. // and it also can be different by the time the callback invocation is
  286. // completed. Requires that *primary_lock be held in exclusive mode; it may be
  287. // released and reacquired by the implementation.
  288. MutexRelock relock(*DataGuard());
  289. absl::MutexLock lock(&callback_->guard);
  290. cb();
  291. }
  292. std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() {
  293. absl::MutexLock l(DataGuard());
  294. bool modified = modified_;
  295. bool on_command_line = on_command_line_;
  296. switch (ValueStorageKind()) {
  297. case FlagValueStorageKind::kValueAndInitBit:
  298. case FlagValueStorageKind::kOneWordAtomic: {
  299. return absl::make_unique<FlagState>(
  300. *this, OneWordValue().load(std::memory_order_acquire), modified,
  301. on_command_line, ModificationCount());
  302. }
  303. case FlagValueStorageKind::kSequenceLocked: {
  304. void* cloned = flags_internal::Alloc(op_);
  305. // Read is guaranteed to be successful because we hold the lock.
  306. bool success =
  307. seq_lock_.TryRead(cloned, AtomicBufferValue(), Sizeof(op_));
  308. assert(success);
  309. static_cast<void>(success);
  310. return absl::make_unique<FlagState>(*this, cloned, modified,
  311. on_command_line, ModificationCount());
  312. }
  313. case FlagValueStorageKind::kAlignedBuffer: {
  314. return absl::make_unique<FlagState>(
  315. *this, flags_internal::Clone(op_, AlignedBufferValue()), modified,
  316. on_command_line, ModificationCount());
  317. }
  318. }
  319. return nullptr;
  320. }
  321. bool FlagImpl::RestoreState(const FlagState& flag_state) {
  322. absl::MutexLock l(DataGuard());
  323. if (flag_state.counter_ == ModificationCount()) {
  324. return false;
  325. }
  326. switch (ValueStorageKind()) {
  327. case FlagValueStorageKind::kValueAndInitBit:
  328. case FlagValueStorageKind::kOneWordAtomic:
  329. StoreValue(&flag_state.value_.one_word);
  330. break;
  331. case FlagValueStorageKind::kSequenceLocked:
  332. case FlagValueStorageKind::kAlignedBuffer:
  333. StoreValue(flag_state.value_.heap_allocated);
  334. break;
  335. }
  336. modified_ = flag_state.modified_;
  337. on_command_line_ = flag_state.on_command_line_;
  338. return true;
  339. }
  340. template <typename StorageT>
  341. StorageT* FlagImpl::OffsetValue() const {
  342. char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this));
  343. // The offset is deduced via Flag value type specific op_.
  344. size_t offset = flags_internal::ValueOffset(op_);
  345. return reinterpret_cast<StorageT*>(p + offset);
  346. }
  347. void* FlagImpl::AlignedBufferValue() const {
  348. assert(ValueStorageKind() == FlagValueStorageKind::kAlignedBuffer);
  349. return OffsetValue<void>();
  350. }
  351. std::atomic<uint64_t>* FlagImpl::AtomicBufferValue() const {
  352. assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked);
  353. return OffsetValue<std::atomic<uint64_t>>();
  354. }
  355. std::atomic<int64_t>& FlagImpl::OneWordValue() const {
  356. assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic ||
  357. ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit);
  358. return OffsetValue<FlagOneWordValue>()->value;
  359. }
  360. // Attempts to parse supplied `value` string using parsing routine in the `flag`
  361. // argument. If parsing successful, this function replaces the dst with newly
  362. // parsed value. In case if any error is encountered in either step, the error
  363. // message is stored in 'err'
  364. std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse(
  365. absl::string_view value, std::string& err) const {
  366. std::unique_ptr<void, DynValueDeleter> tentative_value = MakeInitValue();
  367. std::string parse_err;
  368. if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) {
  369. absl::string_view err_sep = parse_err.empty() ? "" : "; ";
  370. err = absl::StrCat("Illegal value '", value, "' specified for flag '",
  371. Name(), "'", err_sep, parse_err);
  372. return nullptr;
  373. }
  374. return tentative_value;
  375. }
  376. void FlagImpl::Read(void* dst) const {
  377. auto* guard = DataGuard(); // Make sure flag initialized
  378. switch (ValueStorageKind()) {
  379. case FlagValueStorageKind::kValueAndInitBit:
  380. case FlagValueStorageKind::kOneWordAtomic: {
  381. const int64_t one_word_val =
  382. OneWordValue().load(std::memory_order_acquire);
  383. std::memcpy(dst, &one_word_val, Sizeof(op_));
  384. break;
  385. }
  386. case FlagValueStorageKind::kSequenceLocked: {
  387. ReadSequenceLockedData(dst);
  388. break;
  389. }
  390. case FlagValueStorageKind::kAlignedBuffer: {
  391. absl::MutexLock l(guard);
  392. flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst);
  393. break;
  394. }
  395. }
  396. }
  397. int64_t FlagImpl::ReadOneWord() const {
  398. assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic ||
  399. ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit);
  400. auto* guard = DataGuard(); // Make sure flag initialized
  401. (void)guard;
  402. return OneWordValue().load(std::memory_order_acquire);
  403. }
  404. bool FlagImpl::ReadOneBool() const {
  405. assert(ValueStorageKind() == FlagValueStorageKind::kValueAndInitBit);
  406. auto* guard = DataGuard(); // Make sure flag initialized
  407. (void)guard;
  408. return absl::bit_cast<FlagValueAndInitBit<bool>>(
  409. OneWordValue().load(std::memory_order_acquire))
  410. .value;
  411. }
  412. void FlagImpl::ReadSequenceLockedData(void* dst) const {
  413. int size = Sizeof(op_);
  414. // Attempt to read using the sequence lock.
  415. if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) {
  416. return;
  417. }
  418. // We failed due to contention. Acquire the lock to prevent contention
  419. // and try again.
  420. absl::ReaderMutexLock l(DataGuard());
  421. bool success = seq_lock_.TryRead(dst, AtomicBufferValue(), size);
  422. assert(success);
  423. static_cast<void>(success);
  424. }
  425. void FlagImpl::Write(const void* src) {
  426. absl::MutexLock l(DataGuard());
  427. if (ShouldValidateFlagValue(flags_internal::FastTypeId(op_))) {
  428. std::unique_ptr<void, DynValueDeleter> obj{flags_internal::Clone(op_, src),
  429. DynValueDeleter{op_}};
  430. std::string ignored_error;
  431. std::string src_as_str = flags_internal::Unparse(op_, src);
  432. if (!flags_internal::Parse(op_, src_as_str, obj.get(), &ignored_error)) {
  433. ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
  434. "' to invalid value ", src_as_str));
  435. }
  436. }
  437. StoreValue(src);
  438. }
  439. // Sets the value of the flag based on specified string `value`. If the flag
  440. // was successfully set to new value, it returns true. Otherwise, sets `err`
  441. // to indicate the error, leaves the flag unchanged, and returns false. There
  442. // are three ways to set the flag's value:
  443. // * Update the current flag value
  444. // * Update the flag's default value
  445. // * Update the current flag value if it was never set before
  446. // The mode is selected based on 'set_mode' parameter.
  447. bool FlagImpl::ParseFrom(absl::string_view value, FlagSettingMode set_mode,
  448. ValueSource source, std::string& err) {
  449. absl::MutexLock l(DataGuard());
  450. switch (set_mode) {
  451. case SET_FLAGS_VALUE: {
  452. // set or modify the flag's value
  453. auto tentative_value = TryParse(value, err);
  454. if (!tentative_value) return false;
  455. StoreValue(tentative_value.get());
  456. if (source == kCommandLine) {
  457. on_command_line_ = true;
  458. }
  459. break;
  460. }
  461. case SET_FLAG_IF_DEFAULT: {
  462. // set the flag's value, but only if it hasn't been set by someone else
  463. if (modified_) {
  464. // TODO(rogeeff): review and fix this semantic. Currently we do not fail
  465. // in this case if flag is modified. This is misleading since the flag's
  466. // value is not updated even though we return true.
  467. // *err = absl::StrCat(Name(), " is already set to ",
  468. // CurrentValue(), "\n");
  469. // return false;
  470. return true;
  471. }
  472. auto tentative_value = TryParse(value, err);
  473. if (!tentative_value) return false;
  474. StoreValue(tentative_value.get());
  475. break;
  476. }
  477. case SET_FLAGS_DEFAULT: {
  478. auto tentative_value = TryParse(value, err);
  479. if (!tentative_value) return false;
  480. if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
  481. void* old_value = default_value_.dynamic_value;
  482. default_value_.dynamic_value = tentative_value.release();
  483. tentative_value.reset(old_value);
  484. } else {
  485. default_value_.dynamic_value = tentative_value.release();
  486. def_kind_ = static_cast<uint8_t>(FlagDefaultKind::kDynamicValue);
  487. }
  488. if (!modified_) {
  489. // Need to set both default value *and* current, in this case.
  490. StoreValue(default_value_.dynamic_value);
  491. modified_ = false;
  492. }
  493. break;
  494. }
  495. }
  496. return true;
  497. }
  498. void FlagImpl::CheckDefaultValueParsingRoundtrip() const {
  499. std::string v = DefaultValue();
  500. absl::MutexLock lock(DataGuard());
  501. auto dst = MakeInitValue();
  502. std::string error;
  503. if (!flags_internal::Parse(op_, v, dst.get(), &error)) {
  504. ABSL_INTERNAL_LOG(
  505. FATAL,
  506. absl::StrCat("Flag ", Name(), " (from ", Filename(),
  507. "): string form of default value '", v,
  508. "' could not be parsed; error=", error));
  509. }
  510. // We do not compare dst to def since parsing/unparsing may make
  511. // small changes, e.g., precision loss for floating point types.
  512. }
  513. bool FlagImpl::ValidateInputValue(absl::string_view value) const {
  514. absl::MutexLock l(DataGuard());
  515. auto obj = MakeInitValue();
  516. std::string ignored_error;
  517. return flags_internal::Parse(op_, value, obj.get(), &ignored_error);
  518. }
  519. } // namespace flags_internal
  520. ABSL_NAMESPACE_END
  521. } // namespace absl