Export of internal Abseil changes
-- b770d03c2f1042d399c3f9576e881691cbe962c4 by Abseil Team <absl-team@google.com>: Avoid applying the workaround for MSVC's static initialization problems when using clang-cl. PiperOrigin-RevId: 275870089 -- 2b8fc02ec49aeb5ad56cef20259cdd7f6ee0c917 by Abseil Team <absl-team@google.com>: Document return values. PiperOrigin-RevId: 275839042 -- baa99064f9a28b188661df7fba989fcd558818af by Abseil Team <absl-team@google.com>: Support "auto" and other uncommon builtin types in absl::debugging_internal::Demangle. PiperOrigin-RevId: 275556195 -- f9d5c6a3a0d374dbf105d6e2e9e0c8fa949ed187 by Gennadiy Rozental <rogeeff@google.com>: Internal rework. PiperOrigin-RevId: 275550005 -- 2679a77db5b26349e8c8b2059621af55d2fca139 by Mark Barolak <mbar@google.com>: Remove a comment reference to the no longer extant ::string implementation. PiperOrigin-RevId: 275531987 -- 7b427a7613c44a98c6f13da43b2bff2837ca6b19 by Derek Mauro <dmauro@google.com>: Upgrade to Bazel 1.0.0 and CMake 3.15.4 PiperOrigin-RevId: 275500823 -- 81f7d20905debf9d1e300bd2e9899f88d27f632a by Derek Mauro <dmauro@google.com>: Fix -Wimplicit-int-float-conversion warning in latest clang PiperOrigin-RevId: 275492439 GitOrigin-RevId: b770d03c2f1042d399c3f9576e881691cbe962c4 Change-Id: I9b39dad524489f0d62c912d02e8ac43761c81e55
This commit is contained in:
parent
e4c8d0eb8e
commit
2796d500ae
23 changed files with 639 additions and 635 deletions
|
@ -93,6 +93,8 @@ static const AbbrevPair kOperatorList[] = {
|
|||
};
|
||||
|
||||
// List of builtin types from Itanium C++ ABI.
|
||||
//
|
||||
// Invariant: only one- or two-character type abbreviations here.
|
||||
static const AbbrevPair kBuiltinTypeList[] = {
|
||||
{"v", "void", 0},
|
||||
{"w", "wchar_t", 0},
|
||||
|
@ -115,6 +117,16 @@ static const AbbrevPair kBuiltinTypeList[] = {
|
|||
{"e", "long double", 0},
|
||||
{"g", "__float128", 0},
|
||||
{"z", "ellipsis", 0},
|
||||
|
||||
{"De", "decimal128", 0}, // IEEE 754r decimal floating point (128 bits)
|
||||
{"Dd", "decimal64", 0}, // IEEE 754r decimal floating point (64 bits)
|
||||
{"Dc", "decltype(auto)", 0},
|
||||
{"Da", "auto", 0},
|
||||
{"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr)
|
||||
{"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits)
|
||||
{"Di", "char32_t", 0},
|
||||
{"Ds", "char16_t", 0},
|
||||
{"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits)
|
||||
{nullptr, nullptr, 0},
|
||||
};
|
||||
|
||||
|
@ -1168,12 +1180,6 @@ static bool ParseType(State *state) {
|
|||
}
|
||||
state->parse_state = copy;
|
||||
|
||||
// nullptr_t, i.e. decltype(nullptr).
|
||||
if (ParseTwoCharToken(state, "Dn")) {
|
||||
return true;
|
||||
}
|
||||
state->parse_state = copy;
|
||||
|
||||
if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
|
||||
ParseType(state)) {
|
||||
return true;
|
||||
|
@ -1214,16 +1220,26 @@ static bool ParseCVQualifiers(State *state) {
|
|||
return num_cv_qualifiers > 0;
|
||||
}
|
||||
|
||||
// <builtin-type> ::= v, etc.
|
||||
// <builtin-type> ::= v, etc. # single-character builtin types
|
||||
// ::= u <source-name>
|
||||
// ::= Dd, etc. # two-character builtin types
|
||||
//
|
||||
// Not supported:
|
||||
// ::= DF <number> _ # _FloatN (N bits)
|
||||
//
|
||||
static bool ParseBuiltinType(State *state) {
|
||||
ComplexityGuard guard(state);
|
||||
if (guard.IsTooComplex()) return false;
|
||||
const AbbrevPair *p;
|
||||
for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
|
||||
if (RemainingInput(state)[0] == p->abbrev[0]) {
|
||||
// Guaranteed only 1- or 2-character strings in kBuiltinTypeList.
|
||||
if (p->abbrev[1] == '\0') {
|
||||
if (ParseOneCharToken(state, p->abbrev[0])) {
|
||||
MaybeAppend(state, p->real_name);
|
||||
return true;
|
||||
}
|
||||
} else if (p->abbrev[2] == '\0' && ParseTwoCharToken(state, p->abbrev)) {
|
||||
MaybeAppend(state, p->real_name);
|
||||
++state->parse_state.mangled_idx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,10 +36,10 @@ namespace absl {
|
|||
// GetStackFrames()
|
||||
//
|
||||
// Records program counter values for up to `max_depth` frames, skipping the
|
||||
// most recent `skip_count` stack frames, and stores their corresponding values
|
||||
// and sizes in `results` and `sizes` buffers. (Note that the frame generated
|
||||
// for the `absl::GetStackFrames()` routine itself is also skipped.)
|
||||
// routine itself.
|
||||
// most recent `skip_count` stack frames, stores their corresponding values
|
||||
// and sizes in `results` and `sizes` buffers, and returns the number of frames
|
||||
// stored. (Note that the frame generated for the `absl::GetStackFrames()`
|
||||
// routine itself is also skipped.)
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
|
@ -54,8 +54,8 @@ namespace absl {
|
|||
// The current stack frame would consist of three function calls: `bar()`,
|
||||
// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
|
||||
// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently
|
||||
// invoked function call. It will therefore return two program counters and will
|
||||
// produce values that map to the following function calls:
|
||||
// invoked function call. It will therefore return 2 and fill `result` with
|
||||
// program counters within the following functions:
|
||||
//
|
||||
// result[0] foo()
|
||||
// result[1] main()
|
||||
|
@ -82,9 +82,10 @@ extern int GetStackFrames(void** result, int* sizes, int max_depth,
|
|||
//
|
||||
// Records program counter values obtained from a signal handler. Records
|
||||
// program counter values for up to `max_depth` frames, skipping the most recent
|
||||
// `skip_count` stack frames, and stores their corresponding values and sizes in
|
||||
// `results` and `sizes` buffers. (Note that the frame generated for the
|
||||
// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
||||
// `skip_count` stack frames, stores their corresponding values and sizes in
|
||||
// `results` and `sizes` buffers, and returns the number of frames stored. (Note
|
||||
// that the frame generated for the `absl::GetStackFramesWithContext()` routine
|
||||
// itself is also skipped.)
|
||||
//
|
||||
// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
|
||||
// passed to a signal handler registered via the `sa_sigaction` field of a
|
||||
|
@ -105,8 +106,9 @@ extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
|
|||
// GetStackTrace()
|
||||
//
|
||||
// Records program counter values for up to `max_depth` frames, skipping the
|
||||
// most recent `skip_count` stack frames, and stores their corresponding values
|
||||
// in `results`. Note that this function is similar to `absl::GetStackFrames()`
|
||||
// most recent `skip_count` stack frames, stores their corresponding values
|
||||
// in `results`, and returns the number of frames
|
||||
// stored. Note that this function is similar to `absl::GetStackFrames()`
|
||||
// except that it returns the stack trace only, and not stack frame sizes.
|
||||
//
|
||||
// Example:
|
||||
|
@ -131,9 +133,9 @@ extern int GetStackTrace(void** result, int max_depth, int skip_count);
|
|||
//
|
||||
// Records program counter values obtained from a signal handler. Records
|
||||
// program counter values for up to `max_depth` frames, skipping the most recent
|
||||
// `skip_count` stack frames, and stores their corresponding values in
|
||||
// `results`. (Note that the frame generated for the
|
||||
// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
||||
// `skip_count` stack frames, stores their corresponding values in `results`,
|
||||
// and returns the number of frames stored. (Note that the frame generated for
|
||||
// the `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
||||
//
|
||||
// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
|
||||
// passed to a signal handler registered via the `sa_sigaction` field of a
|
||||
|
|
|
@ -40,6 +40,7 @@ cc_library(
|
|||
deps = [
|
||||
":handle",
|
||||
":registry",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/memory",
|
||||
"//absl/strings",
|
||||
"//absl/synchronization",
|
||||
|
@ -135,9 +136,6 @@ cc_library(
|
|||
":config",
|
||||
":marshalling",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/strings",
|
||||
"//absl/synchronization",
|
||||
"//absl/types:optional",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -39,7 +39,7 @@ class Flag;
|
|||
// Flag
|
||||
//
|
||||
// Forward declaration of the `absl::Flag` type for use in defining the macro.
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
template <typename T>
|
||||
class Flag;
|
||||
#else
|
||||
|
|
|
@ -43,7 +43,7 @@ ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_ATOMIC_GET)
|
|||
|
||||
// This global nutex protects on-demand construction of flag objects in MSVC
|
||||
// builds.
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
|
||||
namespace flags_internal {
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace absl {
|
|||
// ABSL_FLAG(int, count, 0, "Count of items to process");
|
||||
//
|
||||
// No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
|
||||
#if !defined(_MSC_VER)
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
template <typename T>
|
||||
using Flag = flags_internal::Flag<T>;
|
||||
#else
|
||||
|
@ -119,7 +119,6 @@ class Flag {
|
|||
absl::string_view Name() const { return GetImpl()->Name(); }
|
||||
std::string Help() const { return GetImpl()->Help(); }
|
||||
bool IsModified() const { return GetImpl()->IsModified(); }
|
||||
void SetModified(bool is_modified) { GetImpl()->SetModified(is_modified); }
|
||||
bool IsSpecifiedOnCommandLine() const {
|
||||
return GetImpl()->IsSpecifiedOnCommandLine();
|
||||
}
|
||||
|
@ -127,9 +126,6 @@ class Flag {
|
|||
std::string Filename() const { return GetImpl()->Filename(); }
|
||||
std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
|
||||
std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
|
||||
bool InvokeValidator(const void* value) const {
|
||||
return GetImpl()->InvokeValidator(value);
|
||||
}
|
||||
template <typename T1>
|
||||
inline bool IsOfType() const {
|
||||
return GetImpl()->template IsOfType<T1>();
|
||||
|
@ -272,7 +268,7 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
|
|||
#if ABSL_FLAGS_STRIP_NAMES
|
||||
#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
|
||||
#define ABSL_FLAG_IMPL_FILENAME() ""
|
||||
#if !defined(_MSC_VER)
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
||||
absl::flags_internal::FlagRegistrar<T, false>(&flag)
|
||||
#else
|
||||
|
@ -282,7 +278,7 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
|
|||
#else
|
||||
#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
|
||||
#define ABSL_FLAG_IMPL_FILENAME() __FILE__
|
||||
#if !defined(_MSC_VER)
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
||||
absl::flags_internal::FlagRegistrar<T, true>(&flag)
|
||||
#else
|
||||
|
|
|
@ -42,15 +42,14 @@ void TestCallback() {}
|
|||
template <typename T>
|
||||
bool TestConstructionFor() {
|
||||
constexpr flags::Flag<T> f1("f1", &TestHelpMsg, "file",
|
||||
&absl::flags_internal::FlagMarshallingOps<T>,
|
||||
&TestMakeDflt<T>);
|
||||
&flags::FlagMarshallingOps<T>, &TestMakeDflt<T>);
|
||||
EXPECT_EQ(f1.Name(), "f1");
|
||||
EXPECT_EQ(f1.Help(), "help");
|
||||
EXPECT_EQ(f1.Filename(), "file");
|
||||
|
||||
ABSL_CONST_INIT static flags::Flag<T> f2(
|
||||
"f2", &TestHelpMsg, "file", &absl::flags_internal::FlagMarshallingOps<T>,
|
||||
&TestMakeDflt<T>);
|
||||
ABSL_CONST_INIT static flags::Flag<T> f2("f2", &TestHelpMsg, "file",
|
||||
&flags::FlagMarshallingOps<T>,
|
||||
&TestMakeDflt<T>);
|
||||
flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
|
||||
|
||||
EXPECT_EQ(f2.Name(), "f2");
|
||||
|
|
|
@ -15,14 +15,7 @@
|
|||
|
||||
#include "absl/flags/internal/commandlineflag.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/flags/config.h"
|
||||
#include "absl/flags/usage_config.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace absl {
|
||||
namespace flags_internal {
|
||||
|
@ -35,80 +28,6 @@ namespace flags_internal {
|
|||
// This is used by this file, and also in commandlineflags_reporting.cc
|
||||
const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
|
||||
|
||||
namespace {
|
||||
|
||||
// Currently we only validate flag values for user-defined flag types.
|
||||
bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
|
||||
#define DONT_VALIDATE(T) \
|
||||
if (flag.IsOfType<T>()) return false;
|
||||
ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
|
||||
DONT_VALIDATE(std::string)
|
||||
DONT_VALIDATE(std::vector<std::string>)
|
||||
#undef DONT_VALIDATE
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
absl::Mutex* InitFlag(CommandLineFlag* flag) {
|
||||
ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
|
||||
absl::Mutex* mu;
|
||||
|
||||
{
|
||||
absl::MutexLock lock(&init_lock);
|
||||
|
||||
if (flag->locks_ == nullptr) { // Must initialize Mutexes for this flag.
|
||||
flag->locks_ = new flags_internal::CommandLineFlagLocks;
|
||||
}
|
||||
|
||||
mu = &flag->locks_->primary_mu;
|
||||
}
|
||||
|
||||
{
|
||||
absl::MutexLock lock(mu);
|
||||
|
||||
if (!flag->IsRetired() && flag->def_ == nullptr) {
|
||||
// Need to initialize def and cur fields.
|
||||
flag->def_ = (*flag->make_init_value_)();
|
||||
flag->cur_ = Clone(flag->op_, flag->def_);
|
||||
UpdateCopy(flag);
|
||||
flag->inited_.store(true, std::memory_order_release);
|
||||
flag->InvokeCallback();
|
||||
}
|
||||
}
|
||||
|
||||
flag->inited_.store(true, std::memory_order_release);
|
||||
return mu;
|
||||
}
|
||||
|
||||
// Ensure that the lazily initialized fields of *flag have been initialized,
|
||||
// and return &flag->locks_->primary_mu.
|
||||
absl::Mutex* CommandLineFlag::InitFlagIfNecessary() const
|
||||
ABSL_LOCK_RETURNED(locks_->primary_mu) {
|
||||
if (!inited_.load(std::memory_order_acquire)) {
|
||||
return InitFlag(const_cast<CommandLineFlag*>(this));
|
||||
}
|
||||
|
||||
// All fields initialized; locks_ is therefore safe to read.
|
||||
return &locks_->primary_mu;
|
||||
}
|
||||
|
||||
bool CommandLineFlag::IsModified() const {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
return modified_;
|
||||
}
|
||||
|
||||
void CommandLineFlag::SetModified(bool is_modified) {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
modified_ = is_modified;
|
||||
}
|
||||
|
||||
bool CommandLineFlag::IsSpecifiedOnCommandLine() const {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
return on_command_line_;
|
||||
}
|
||||
|
||||
absl::string_view CommandLineFlag::Typename() const {
|
||||
// We do not store/report type in Abseil Flags, so that user do not rely on in
|
||||
// at runtime
|
||||
|
@ -137,223 +56,6 @@ std::string CommandLineFlag::Filename() const {
|
|||
return flags_internal::GetUsageConfig().normalize_filename(filename_);
|
||||
}
|
||||
|
||||
std::string CommandLineFlag::DefaultValue() const {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
|
||||
return Unparse(marshalling_op_, def_);
|
||||
}
|
||||
|
||||
std::string CommandLineFlag::CurrentValue() const {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
|
||||
return Unparse(marshalling_op_, cur_);
|
||||
}
|
||||
|
||||
int64_t CommandLineFlag::MutationCounter() const {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
|
||||
return counter_;
|
||||
}
|
||||
|
||||
// Attempts to parse supplied `value` string using parsing routine in the `flag`
|
||||
// argument. If parsing is successful, it will try to validate that the parsed
|
||||
// value is valid for the specified 'flag'. Finally this function stores the
|
||||
// parsed value in 'dst' assuming it is a pointer to the flag's value type. In
|
||||
// case if any error is encountered in either step, the error message is stored
|
||||
// in 'err'
|
||||
bool TryParseLocked(CommandLineFlag* flag, void* dst, absl::string_view value,
|
||||
std::string* err)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(flag->locks_->primary_mu) {
|
||||
void* tentative_value = Clone(flag->op_, flag->def_);
|
||||
std::string parse_err;
|
||||
if (!Parse(flag->marshalling_op_, value, tentative_value, &parse_err)) {
|
||||
auto type_name = flag->Typename();
|
||||
absl::string_view err_sep = parse_err.empty() ? "" : "; ";
|
||||
absl::string_view typename_sep = type_name.empty() ? "" : " ";
|
||||
*err = absl::StrCat("Illegal value '", value, "' specified for",
|
||||
typename_sep, type_name, " flag '", flag->Name(), "'",
|
||||
err_sep, parse_err);
|
||||
Delete(flag->op_, tentative_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!flag->InvokeValidator(tentative_value)) {
|
||||
*err = absl::StrCat("Failed validation of new value '",
|
||||
Unparse(flag->marshalling_op_, tentative_value),
|
||||
"' for flag '", flag->Name(), "'");
|
||||
Delete(flag->op_, tentative_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
flag->counter_++;
|
||||
Copy(flag->op_, tentative_value, dst);
|
||||
Delete(flag->op_, tentative_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sets the value of the flag based on specified string `value`. If the flag
|
||||
// was successfully set to new value, it returns true. Otherwise, sets `err`
|
||||
// to indicate the error, leaves the flag unchanged, and returns false. There
|
||||
// are three ways to set the flag's value:
|
||||
// * Update the current flag value
|
||||
// * Update the flag's default value
|
||||
// * Update the current flag value if it was never set before
|
||||
// The mode is selected based on 'set_mode' parameter.
|
||||
bool CommandLineFlag::SetFromString(absl::string_view value,
|
||||
FlagSettingMode set_mode,
|
||||
ValueSource source, std::string* err) {
|
||||
if (IsRetired()) return false;
|
||||
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
|
||||
// Direct-access flags can be modified without going through the
|
||||
// flag API. Detect such changes and update the flag->modified_ bit.
|
||||
if (!IsAbseilFlag()) {
|
||||
if (!modified_ && ChangedDirectly(this, cur_, def_)) {
|
||||
modified_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (set_mode) {
|
||||
case SET_FLAGS_VALUE: {
|
||||
// set or modify the flag's value
|
||||
if (!TryParseLocked(this, cur_, value, err)) return false;
|
||||
modified_ = true;
|
||||
UpdateCopy(this);
|
||||
InvokeCallback();
|
||||
|
||||
if (source == kCommandLine) {
|
||||
on_command_line_ = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SET_FLAG_IF_DEFAULT: {
|
||||
// set the flag's value, but only if it hasn't been set by someone else
|
||||
if (!modified_) {
|
||||
if (!TryParseLocked(this, cur_, value, err)) return false;
|
||||
modified_ = true;
|
||||
UpdateCopy(this);
|
||||
InvokeCallback();
|
||||
} else {
|
||||
// TODO(rogeeff): review and fix this semantic. Currently we do not fail
|
||||
// in this case if flag is modified. This is misleading since the flag's
|
||||
// value is not updated even though we return true.
|
||||
// *err = absl::StrCat(Name(), " is already set to ",
|
||||
// CurrentValue(), "\n");
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SET_FLAGS_DEFAULT: {
|
||||
// modify the flag's default-value
|
||||
if (!TryParseLocked(this, def_, value, err)) return false;
|
||||
|
||||
if (!modified_) {
|
||||
// Need to set both defvalue *and* current, in this case
|
||||
Copy(op_, def_, cur_);
|
||||
UpdateCopy(this);
|
||||
InvokeCallback();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// unknown set_mode
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandLineFlag::CheckDefaultValueParsingRoundtrip() const {
|
||||
std::string v = DefaultValue();
|
||||
|
||||
absl::MutexLock lock(InitFlagIfNecessary());
|
||||
|
||||
void* dst = Clone(op_, def_);
|
||||
std::string error;
|
||||
if (!flags_internal::Parse(marshalling_op_, v, dst, &error)) {
|
||||
ABSL_INTERNAL_LOG(
|
||||
FATAL,
|
||||
absl::StrCat("Flag ", Name(), " (from ", Filename(),
|
||||
"): std::string form of default value '", v,
|
||||
"' could not be parsed; error=", error));
|
||||
}
|
||||
|
||||
// We do not compare dst to def since parsing/unparsing may make
|
||||
// small changes, e.g., precision loss for floating point types.
|
||||
Delete(op_, dst);
|
||||
}
|
||||
|
||||
bool CommandLineFlag::ValidateDefaultValue() const {
|
||||
absl::MutexLock lock(InitFlagIfNecessary());
|
||||
return InvokeValidator(def_);
|
||||
}
|
||||
|
||||
bool CommandLineFlag::ValidateInputValue(absl::string_view value) const {
|
||||
absl::MutexLock l(InitFlagIfNecessary()); // protect default value access
|
||||
|
||||
void* obj = Clone(op_, def_);
|
||||
std::string ignored_error;
|
||||
const bool result =
|
||||
flags_internal::Parse(marshalling_op_, value, obj, &ignored_error) &&
|
||||
InvokeValidator(obj);
|
||||
Delete(op_, obj);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CommandLineFlag::Read(void* dst,
|
||||
const flags_internal::FlagOpFn dst_op) const {
|
||||
absl::ReaderMutexLock l(InitFlagIfNecessary());
|
||||
|
||||
// `dst_op` is the unmarshaling operation corresponding to the declaration
|
||||
// visibile at the call site. `op` is the Flag's defined unmarshalling
|
||||
// operation. They must match for this operation to be well-defined.
|
||||
if (ABSL_PREDICT_FALSE(dst_op != op_)) {
|
||||
ABSL_INTERNAL_LOG(
|
||||
ERROR,
|
||||
absl::StrCat("Flag '", Name(),
|
||||
"' is defined as one type and declared as another"));
|
||||
}
|
||||
CopyConstruct(op_, cur_, dst);
|
||||
}
|
||||
|
||||
void CommandLineFlag::Write(const void* src,
|
||||
const flags_internal::FlagOpFn src_op) {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
|
||||
// `src_op` is the marshalling operation corresponding to the declaration
|
||||
// visible at the call site. `op` is the Flag's defined marshalling operation.
|
||||
// They must match for this operation to be well-defined.
|
||||
if (ABSL_PREDICT_FALSE(src_op != op_)) {
|
||||
ABSL_INTERNAL_LOG(
|
||||
ERROR,
|
||||
absl::StrCat("Flag '", Name(),
|
||||
"' is defined as one type and declared as another"));
|
||||
}
|
||||
|
||||
if (ShouldValidateFlagValue(*this)) {
|
||||
void* obj = Clone(op_, src);
|
||||
std::string ignored_error;
|
||||
std::string src_as_str = Unparse(marshalling_op_, src);
|
||||
if (!Parse(marshalling_op_, src_as_str, obj, &ignored_error) ||
|
||||
!InvokeValidator(obj)) {
|
||||
ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
|
||||
"' to invalid value ", src_as_str));
|
||||
}
|
||||
Delete(op_, obj);
|
||||
}
|
||||
|
||||
modified_ = true;
|
||||
counter_++;
|
||||
Copy(op_, src, cur_);
|
||||
|
||||
UpdateCopy(this);
|
||||
InvokeCallback();
|
||||
}
|
||||
|
||||
std::string HelpText::GetHelpText() const {
|
||||
if (help_function_) return help_function_();
|
||||
if (help_message_) return help_message_;
|
||||
|
@ -361,40 +63,5 @@ std::string HelpText::GetHelpText() const {
|
|||
return {};
|
||||
}
|
||||
|
||||
// Update any copy of the flag value that is stored in an atomic word.
|
||||
// In addition if flag has a mutation callback this function invokes it.
|
||||
void UpdateCopy(CommandLineFlag* flag) {
|
||||
#define STORE_ATOMIC(T) \
|
||||
else if (flag->IsOfType<T>()) { \
|
||||
flag->StoreAtomic(); \
|
||||
}
|
||||
|
||||
if (false) {
|
||||
}
|
||||
ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(STORE_ATOMIC)
|
||||
#undef STORE_ATOMIC
|
||||
}
|
||||
|
||||
// Return true iff flag value was changed via direct-access.
|
||||
bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b) {
|
||||
if (!flag->IsAbseilFlag()) {
|
||||
// Need to compare values for direct-access flags.
|
||||
#define CHANGED_FOR_TYPE(T) \
|
||||
if (flag->IsOfType<T>()) { \
|
||||
return *reinterpret_cast<const T*>(a) != *reinterpret_cast<const T*>(b); \
|
||||
}
|
||||
|
||||
CHANGED_FOR_TYPE(bool);
|
||||
CHANGED_FOR_TYPE(int32_t);
|
||||
CHANGED_FOR_TYPE(int64_t);
|
||||
CHANGED_FOR_TYPE(uint64_t);
|
||||
CHANGED_FOR_TYPE(double);
|
||||
CHANGED_FOR_TYPE(std::string);
|
||||
#undef CHANGED_FOR_TYPE
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace flags_internal
|
||||
} // namespace absl
|
||||
|
|
|
@ -16,12 +16,10 @@
|
|||
#ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
||||
#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/flags/marshalling.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
|
@ -151,14 +149,6 @@ inline size_t Sizeof(FlagOpFn op) {
|
|||
op(flags_internal::kSizeof, nullptr, nullptr)));
|
||||
}
|
||||
|
||||
// The following struct contains the locks in a CommandLineFlag struct.
|
||||
// They are in a separate struct that is lazily allocated to avoid problems
|
||||
// with static initialization and to avoid multiple allocations.
|
||||
struct CommandLineFlagLocks {
|
||||
absl::Mutex primary_mu; // protects several fields in CommandLineFlag
|
||||
absl::Mutex callback_mu; // used to serialize callbacks
|
||||
};
|
||||
|
||||
// Holds either a pointer to help text or a function which produces it. This is
|
||||
// needed for supporting both static initialization of Flags while supporting
|
||||
// the legacy registration framework. We can't use absl::variant<const char*,
|
||||
|
@ -200,25 +190,9 @@ class FlagStateInterface {
|
|||
// Holds all information for a flag.
|
||||
class CommandLineFlag {
|
||||
public:
|
||||
constexpr CommandLineFlag(
|
||||
const char* name, HelpText help_text, const char* filename,
|
||||
const flags_internal::FlagOpFn op,
|
||||
const flags_internal::FlagMarshallingOpFn marshalling_op,
|
||||
const flags_internal::InitialValGenFunc initial_value_gen, void* def,
|
||||
void* cur)
|
||||
: name_(name),
|
||||
help_(help_text),
|
||||
filename_(filename),
|
||||
op_(op),
|
||||
marshalling_op_(marshalling_op),
|
||||
make_init_value_(initial_value_gen),
|
||||
inited_(false),
|
||||
modified_(false),
|
||||
on_command_line_(false),
|
||||
def_(def),
|
||||
cur_(cur),
|
||||
counter_(0),
|
||||
locks_(nullptr) {}
|
||||
constexpr CommandLineFlag(const char* name, HelpText help_text,
|
||||
const char* filename)
|
||||
: name_(name), help_(help_text), filename_(filename) {}
|
||||
|
||||
// Virtual destructor
|
||||
virtual void Destroy() const = 0;
|
||||
|
@ -227,60 +201,73 @@ class CommandLineFlag {
|
|||
CommandLineFlag(const CommandLineFlag&) = delete;
|
||||
CommandLineFlag& operator=(const CommandLineFlag&) = delete;
|
||||
|
||||
// Access methods.
|
||||
|
||||
// Returns true iff this object corresponds to retired flag
|
||||
virtual bool IsRetired() const { return false; }
|
||||
// Returns true iff this is a handle to an Abseil Flag.
|
||||
virtual bool IsAbseilFlag() const { return true; }
|
||||
|
||||
// Non-polymorphic access methods.
|
||||
absl::string_view Name() const { return name_; }
|
||||
std::string Help() const { return help_.GetHelpText(); }
|
||||
bool IsModified() const;
|
||||
void SetModified(bool is_modified);
|
||||
bool IsSpecifiedOnCommandLine() const;
|
||||
|
||||
absl::string_view Typename() const;
|
||||
std::string Filename() const;
|
||||
std::string DefaultValue() const;
|
||||
std::string CurrentValue() const;
|
||||
|
||||
// Interface to store the value in atomic if one used. This is short term
|
||||
// interface. To be reworked once cur_ is moved.
|
||||
virtual void StoreAtomic() {}
|
||||
|
||||
// Interfaces to operate on validators.
|
||||
virtual bool InvokeValidator(const void* /*value*/) const { return true; }
|
||||
// Invoke the flag validators for old flags.
|
||||
// TODO(rogeeff): implement proper validators for Abseil Flags
|
||||
bool ValidateDefaultValue() const;
|
||||
bool ValidateInputValue(absl::string_view value) const;
|
||||
|
||||
// Return true iff flag has type T.
|
||||
template <typename T>
|
||||
inline bool IsOfType() const {
|
||||
return op_ == &flags_internal::FlagOps<T>;
|
||||
return TypeId() == &flags_internal::FlagOps<T>;
|
||||
}
|
||||
|
||||
// Attempts to retrieve the flag value. Returns value on success,
|
||||
// absl::nullopt otherwise.
|
||||
template <typename T>
|
||||
absl::optional<T> Get() const {
|
||||
if (IsRetired() || flags_internal::FlagOps<T> != op_) return absl::nullopt;
|
||||
if (IsRetired() || !IsOfType<T>()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
T res;
|
||||
Read(&res, flags_internal::FlagOps<T>);
|
||||
// Implementation notes:
|
||||
//
|
||||
// We are wrapping a union around the value of `T` to serve three purposes:
|
||||
//
|
||||
// 1. `U.value` has correct size and alignment for a value of type `T`
|
||||
// 2. The `U.value` constructor is not invoked since U's constructor does
|
||||
// not
|
||||
// do it explicitly.
|
||||
// 3. The `U.value` destructor is invoked since U's destructor does it
|
||||
// explicitly. This makes `U` a kind of RAII wrapper around non default
|
||||
// constructible value of T, which is destructed when we leave the
|
||||
// scope. We do need to destroy U.value, which is constructed by
|
||||
// CommandLineFlag::Read even though we left it in a moved-from state
|
||||
// after std::move.
|
||||
//
|
||||
// All of this serves to avoid requiring `T` being default constructible.
|
||||
union U {
|
||||
T value;
|
||||
U() {}
|
||||
~U() { value.~T(); }
|
||||
};
|
||||
U u;
|
||||
|
||||
return res;
|
||||
Read(&u.value);
|
||||
return std::move(u.value);
|
||||
}
|
||||
|
||||
// Polymorphic access methods
|
||||
|
||||
// Returns true iff this object corresponds to retired flag
|
||||
virtual bool IsRetired() const { return false; }
|
||||
// Returns true iff this is a handle to an Abseil Flag.
|
||||
virtual bool IsAbseilFlag() const { return true; }
|
||||
// Returns id of the flag's value type.
|
||||
virtual flags_internal::FlagOpFn TypeId() const = 0;
|
||||
virtual bool IsModified() const = 0;
|
||||
virtual bool IsSpecifiedOnCommandLine() const = 0;
|
||||
virtual std::string DefaultValue() const = 0;
|
||||
virtual std::string CurrentValue() const = 0;
|
||||
|
||||
// Interfaces to operate on validators.
|
||||
virtual bool ValidateInputValue(absl::string_view value) const = 0;
|
||||
|
||||
// Interface to save flag to some persistent state. Returns current flag state
|
||||
// or nullptr if flag does not support saving and restoring a state.
|
||||
virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
|
||||
|
||||
// Interfaces to overate on callbacks.
|
||||
virtual void InvokeCallback() {}
|
||||
|
||||
// Sets the value of the flag based on specified std::string `value`. If the flag
|
||||
// was successfully set to new value, it returns true. Otherwise, sets `error`
|
||||
// to indicate the error, leaves the flag unchanged, and returns false. There
|
||||
|
@ -289,75 +276,29 @@ class CommandLineFlag {
|
|||
// * Update the flag's default value
|
||||
// * Update the current flag value if it was never set before
|
||||
// The mode is selected based on `set_mode` parameter.
|
||||
bool SetFromString(absl::string_view value,
|
||||
flags_internal::FlagSettingMode set_mode,
|
||||
flags_internal::ValueSource source, std::string* error);
|
||||
virtual bool SetFromString(absl::string_view value,
|
||||
flags_internal::FlagSettingMode set_mode,
|
||||
flags_internal::ValueSource source,
|
||||
std::string* error) = 0;
|
||||
|
||||
void CheckDefaultValueParsingRoundtrip() const;
|
||||
// Checks that flags default value can be converted to std::string and back to the
|
||||
// flag's value type.
|
||||
virtual void CheckDefaultValueParsingRoundtrip() const = 0;
|
||||
|
||||
// Constant configuration for a particular flag.
|
||||
protected:
|
||||
~CommandLineFlag() = default;
|
||||
|
||||
// Thread safe access to mutation counter.
|
||||
int64_t MutationCounter() const;
|
||||
const char* const name_; // Flags name passed to ABSL_FLAG as second arg.
|
||||
const HelpText help_; // The function generating help message.
|
||||
const char* const filename_; // The file name where ABSL_FLAG resides.
|
||||
|
||||
const char* const name_;
|
||||
const HelpText help_;
|
||||
const char* const filename_;
|
||||
|
||||
const FlagOpFn op_; // Type-specific handler
|
||||
const FlagMarshallingOpFn marshalling_op_; // Marshalling ops handler
|
||||
const InitialValGenFunc make_init_value_; // Makes initial value for the flag
|
||||
std::atomic<bool> inited_; // fields have been lazily initialized
|
||||
|
||||
// Mutable state (guarded by locks_->primary_mu).
|
||||
bool modified_; // Has flag value been modified?
|
||||
bool on_command_line_; // Specified on command line.
|
||||
void* def_; // Lazily initialized pointer to default value
|
||||
void* cur_; // Lazily initialized pointer to current value
|
||||
int64_t counter_; // Mutation counter
|
||||
|
||||
// Lazily initialized mutexes for this flag value. We cannot inline a
|
||||
// SpinLock or Mutex here because those have non-constexpr constructors and
|
||||
// so would prevent constant initialization of this type.
|
||||
// TODO(rogeeff): fix it once Mutex has constexpr constructor
|
||||
struct CommandLineFlagLocks* locks_; // locks, laziliy allocated.
|
||||
|
||||
// Ensure that the lazily initialized fields of *flag have been initialized,
|
||||
// and return the lock which should be locked when flag's state is mutated.
|
||||
absl::Mutex* InitFlagIfNecessary() const ABSL_LOCK_RETURNED(locks_->primary_mu);
|
||||
|
||||
// copy construct new value of flag's type in a memory referenced by dst
|
||||
// based on current flag's value
|
||||
void Read(void* dst, const flags_internal::FlagOpFn dst_op) const;
|
||||
// updates flag's value to *src (locked)
|
||||
void Write(const void* src, const flags_internal::FlagOpFn src_op);
|
||||
|
||||
friend class FlagRegistry;
|
||||
friend class FlagPtrMap;
|
||||
friend class FlagSaverImpl;
|
||||
friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
|
||||
absl::string_view value, std::string* err);
|
||||
friend absl::Mutex* InitFlag(CommandLineFlag* flag);
|
||||
private:
|
||||
// Copy-construct a new value of the flag's type in a memory referenced by
|
||||
// the dst based on the current flag's value.
|
||||
virtual void Read(void* dst) const = 0;
|
||||
};
|
||||
|
||||
// Update any copy of the flag value that is stored in an atomic word.
|
||||
// In addition if flag has a mutation callback this function invokes it. While
|
||||
// callback is being invoked the primary flag's mutex is unlocked and it is
|
||||
// re-locked back after call to callback is completed. Callback invocation is
|
||||
// guarded by flag's secondary mutex instead which prevents concurrent callback
|
||||
// invocation. Note that it is possible for other thread to grab the primary
|
||||
// lock and update flag's value at any time during the callback invocation.
|
||||
// This is by design. Callback can get a value of the flag if necessary, but it
|
||||
// might be different from the value initiated the callback and it also can be
|
||||
// different by the time the callback invocation is completed.
|
||||
// Requires that *primary_lock be held in exclusive mode; it may be released
|
||||
// and reacquired by the implementation.
|
||||
void UpdateCopy(CommandLineFlag* flag);
|
||||
// Return true iff flag value was changed via direct-access.
|
||||
bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b);
|
||||
|
||||
// This macro is the "source of truth" for the list of supported flag types we
|
||||
// expect to perform lock free operations on. Specifically it generates code,
|
||||
// a one argument macro operating on a type, supplied as a macro argument, for
|
||||
|
|
|
@ -15,36 +15,331 @@
|
|||
|
||||
#include "absl/flags/internal/flag.h"
|
||||
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace absl {
|
||||
namespace flags_internal {
|
||||
namespace {
|
||||
|
||||
// If the flag has a mutation callback this function invokes it. While the
|
||||
// callback is being invoked the primary flag's mutex is unlocked and it is
|
||||
// re-locked back after call to callback is completed. Callback invocation is
|
||||
// guarded by flag's secondary mutex instead which prevents concurrent
|
||||
// callback invocation. Note that it is possible for other thread to grab the
|
||||
// primary lock and update flag's value at any time during the callback
|
||||
// invocation. This is by design. Callback can get a value of the flag if
|
||||
// necessary, but it might be different from the value initiated the callback
|
||||
// and it also can be different by the time the callback invocation is
|
||||
// completed. Requires that *primary_lock be held in exclusive mode; it may be
|
||||
// released and reacquired by the implementation.
|
||||
void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
|
||||
FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu) {
|
||||
if (!cb) return;
|
||||
// Currently we only validate flag values for user-defined flag types.
|
||||
bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
|
||||
#define DONT_VALIDATE(T) \
|
||||
if (flag.IsOfType<T>()) return false;
|
||||
ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
|
||||
DONT_VALIDATE(std::string)
|
||||
DONT_VALIDATE(std::vector<std::string>)
|
||||
#undef DONT_VALIDATE
|
||||
|
||||
// When executing the callback we need the primary flag's mutex to be
|
||||
// unlocked so that callback can retrieve the flag's value.
|
||||
primary_mu->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void FlagImpl::Init() {
|
||||
ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
|
||||
|
||||
{
|
||||
absl::MutexLock lock(callback_mu);
|
||||
cb();
|
||||
absl::MutexLock lock(&init_lock);
|
||||
|
||||
if (locks_ == nullptr) { // Must initialize Mutexes for this flag.
|
||||
locks_ = new FlagImpl::CommandLineFlagLocks;
|
||||
}
|
||||
}
|
||||
|
||||
primary_mu->Lock();
|
||||
absl::MutexLock lock(&locks_->primary_mu);
|
||||
|
||||
if (def_ != nullptr) {
|
||||
inited_.store(true, std::memory_order_release);
|
||||
} else {
|
||||
// Need to initialize def and cur fields.
|
||||
def_ = (*initial_value_gen_)();
|
||||
cur_ = Clone(op_, def_);
|
||||
StoreAtomic();
|
||||
inited_.store(true, std::memory_order_release);
|
||||
InvokeCallback();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures that the lazily initialized data is initialized,
|
||||
// and returns pointer to the mutex guarding flags data.
|
||||
absl::Mutex* FlagImpl::DataGuard() const
|
||||
ABSL_LOCK_RETURNED(locks_->primary_mu) {
|
||||
if (ABSL_PREDICT_FALSE(!inited_.load(std::memory_order_acquire))) {
|
||||
const_cast<FlagImpl*>(this)->Init();
|
||||
}
|
||||
|
||||
// All fields initialized; locks_ is therefore safe to read.
|
||||
return &locks_->primary_mu;
|
||||
}
|
||||
|
||||
void FlagImpl::Destroy() const {
|
||||
{
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
// Values are heap allocated for Abseil Flags.
|
||||
if (cur_) Delete(op_, cur_);
|
||||
if (def_) Delete(op_, def_);
|
||||
}
|
||||
|
||||
delete locks_;
|
||||
}
|
||||
|
||||
bool FlagImpl::IsModified() const {
|
||||
absl::MutexLock l(DataGuard());
|
||||
return modified_;
|
||||
}
|
||||
|
||||
bool FlagImpl::IsSpecifiedOnCommandLine() const {
|
||||
absl::MutexLock l(DataGuard());
|
||||
return on_command_line_;
|
||||
}
|
||||
|
||||
std::string FlagImpl::DefaultValue() const {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
return Unparse(marshalling_op_, def_);
|
||||
}
|
||||
|
||||
std::string FlagImpl::CurrentValue() const {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
return Unparse(marshalling_op_, cur_);
|
||||
}
|
||||
|
||||
void FlagImpl::SetCallback(
|
||||
const flags_internal::FlagCallback mutation_callback) {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
callback_ = mutation_callback;
|
||||
|
||||
InvokeCallback();
|
||||
}
|
||||
|
||||
void FlagImpl::InvokeCallback() const
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
|
||||
if (!callback_) return;
|
||||
|
||||
// If the flag has a mutation callback this function invokes it. While the
|
||||
// callback is being invoked the primary flag's mutex is unlocked and it is
|
||||
// re-locked back after call to callback is completed. Callback invocation is
|
||||
// guarded by flag's secondary mutex instead which prevents concurrent
|
||||
// callback invocation. Note that it is possible for other thread to grab the
|
||||
// primary lock and update flag's value at any time during the callback
|
||||
// invocation. This is by design. Callback can get a value of the flag if
|
||||
// necessary, but it might be different from the value initiated the callback
|
||||
// and it also can be different by the time the callback invocation is
|
||||
// completed. Requires that *primary_lock be held in exclusive mode; it may be
|
||||
// released and reacquired by the implementation.
|
||||
DataGuard()->Unlock();
|
||||
|
||||
{
|
||||
absl::MutexLock lock(&locks_->callback_mu);
|
||||
callback_();
|
||||
}
|
||||
|
||||
DataGuard()->Lock();
|
||||
}
|
||||
|
||||
bool FlagImpl::RestoreState(const CommandLineFlag& flag, const void* value,
|
||||
bool modified, bool on_command_line,
|
||||
int64_t counter) {
|
||||
{
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
if (counter_ == counter) return false;
|
||||
}
|
||||
|
||||
Write(flag, value, op_);
|
||||
|
||||
{
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
modified_ = modified;
|
||||
on_command_line_ = on_command_line;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Attempts to parse supplied `value` string using parsing routine in the `flag`
|
||||
// argument. If parsing successful, this function stores the parsed value in
|
||||
// 'dst' assuming it is a pointer to the flag's value type. In case if any error
|
||||
// is encountered in either step, the error message is stored in 'err'
|
||||
bool FlagImpl::TryParse(const CommandLineFlag& flag, void* dst,
|
||||
absl::string_view value, std::string* err) const
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
|
||||
void* tentative_value = Clone(op_, def_);
|
||||
std::string parse_err;
|
||||
if (!Parse(marshalling_op_, value, tentative_value, &parse_err)) {
|
||||
auto type_name = flag.Typename();
|
||||
absl::string_view err_sep = parse_err.empty() ? "" : "; ";
|
||||
absl::string_view typename_sep = type_name.empty() ? "" : " ";
|
||||
*err = absl::StrCat("Illegal value '", value, "' specified for",
|
||||
typename_sep, type_name, " flag '", flag.Name(), "'",
|
||||
err_sep, parse_err);
|
||||
Delete(op_, tentative_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
Copy(op_, tentative_value, dst);
|
||||
Delete(op_, tentative_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlagImpl::Read(const CommandLineFlag& flag, void* dst,
|
||||
const flags_internal::FlagOpFn dst_op) const {
|
||||
absl::ReaderMutexLock l(DataGuard());
|
||||
|
||||
// `dst_op` is the unmarshaling operation corresponding to the declaration
|
||||
// visibile at the call site. `op` is the Flag's defined unmarshalling
|
||||
// operation. They must match for this operation to be well-defined.
|
||||
if (ABSL_PREDICT_FALSE(dst_op != op_)) {
|
||||
ABSL_INTERNAL_LOG(
|
||||
ERROR,
|
||||
absl::StrCat("Flag '", flag.Name(),
|
||||
"' is defined as one type and declared as another"));
|
||||
}
|
||||
CopyConstruct(op_, cur_, dst);
|
||||
}
|
||||
|
||||
void FlagImpl::StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
|
||||
size_t data_size = Sizeof(op_);
|
||||
|
||||
if (data_size <= sizeof(int64_t)) {
|
||||
int64_t t = 0;
|
||||
std::memcpy(&t, cur_, data_size);
|
||||
atomic_.store(t, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
void FlagImpl::Write(const CommandLineFlag& flag, const void* src,
|
||||
const flags_internal::FlagOpFn src_op) {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
// `src_op` is the marshalling operation corresponding to the declaration
|
||||
// visible at the call site. `op` is the Flag's defined marshalling operation.
|
||||
// They must match for this operation to be well-defined.
|
||||
if (ABSL_PREDICT_FALSE(src_op != op_)) {
|
||||
ABSL_INTERNAL_LOG(
|
||||
ERROR,
|
||||
absl::StrCat("Flag '", flag.Name(),
|
||||
"' is defined as one type and declared as another"));
|
||||
}
|
||||
|
||||
if (ShouldValidateFlagValue(flag)) {
|
||||
void* obj = Clone(op_, src);
|
||||
std::string ignored_error;
|
||||
std::string src_as_str = Unparse(marshalling_op_, src);
|
||||
if (!Parse(marshalling_op_, src_as_str, obj, &ignored_error)) {
|
||||
ABSL_INTERNAL_LOG(ERROR,
|
||||
absl::StrCat("Attempt to set flag '", flag.Name(),
|
||||
"' to invalid value ", src_as_str));
|
||||
}
|
||||
Delete(op_, obj);
|
||||
}
|
||||
|
||||
modified_ = true;
|
||||
counter_++;
|
||||
Copy(op_, src, cur_);
|
||||
|
||||
StoreAtomic();
|
||||
InvokeCallback();
|
||||
}
|
||||
|
||||
// Sets the value of the flag based on specified string `value`. If the flag
|
||||
// was successfully set to new value, it returns true. Otherwise, sets `err`
|
||||
// to indicate the error, leaves the flag unchanged, and returns false. There
|
||||
// are three ways to set the flag's value:
|
||||
// * Update the current flag value
|
||||
// * Update the flag's default value
|
||||
// * Update the current flag value if it was never set before
|
||||
// The mode is selected based on 'set_mode' parameter.
|
||||
bool FlagImpl::SetFromString(const CommandLineFlag& flag,
|
||||
absl::string_view value, FlagSettingMode set_mode,
|
||||
ValueSource source, std::string* err) {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
switch (set_mode) {
|
||||
case SET_FLAGS_VALUE: {
|
||||
// set or modify the flag's value
|
||||
if (!TryParse(flag, cur_, value, err)) return false;
|
||||
modified_ = true;
|
||||
counter_++;
|
||||
StoreAtomic();
|
||||
InvokeCallback();
|
||||
|
||||
if (source == kCommandLine) {
|
||||
on_command_line_ = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SET_FLAG_IF_DEFAULT: {
|
||||
// set the flag's value, but only if it hasn't been set by someone else
|
||||
if (!modified_) {
|
||||
if (!TryParse(flag, cur_, value, err)) return false;
|
||||
modified_ = true;
|
||||
counter_++;
|
||||
StoreAtomic();
|
||||
InvokeCallback();
|
||||
} else {
|
||||
// TODO(rogeeff): review and fix this semantic. Currently we do not fail
|
||||
// in this case if flag is modified. This is misleading since the flag's
|
||||
// value is not updated even though we return true.
|
||||
// *err = absl::StrCat(Name(), " is already set to ",
|
||||
// CurrentValue(), "\n");
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SET_FLAGS_DEFAULT: {
|
||||
// modify the flag's default-value
|
||||
if (!TryParse(flag, def_, value, err)) return false;
|
||||
|
||||
if (!modified_) {
|
||||
// Need to set both default value *and* current, in this case
|
||||
Copy(op_, def_, cur_);
|
||||
StoreAtomic();
|
||||
InvokeCallback();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlagImpl::CheckDefaultValueParsingRoundtrip(
|
||||
const CommandLineFlag& flag) const {
|
||||
std::string v = DefaultValue();
|
||||
|
||||
absl::MutexLock lock(DataGuard());
|
||||
|
||||
void* dst = Clone(op_, def_);
|
||||
std::string error;
|
||||
if (!flags_internal::Parse(marshalling_op_, v, dst, &error)) {
|
||||
ABSL_INTERNAL_LOG(
|
||||
FATAL,
|
||||
absl::StrCat("Flag ", flag.Name(), " (from ", flag.Filename(),
|
||||
"): std::string form of default value '", v,
|
||||
"' could not be parsed; error=", error));
|
||||
}
|
||||
|
||||
// We do not compare dst to def since parsing/unparsing may make
|
||||
// small changes, e.g., precision loss for floating point types.
|
||||
Delete(op_, dst);
|
||||
}
|
||||
|
||||
bool FlagImpl::ValidateInputValue(absl::string_view value) const {
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
void* obj = Clone(op_, def_);
|
||||
std::string ignored_error;
|
||||
const bool result =
|
||||
flags_internal::Parse(marshalling_op_, value, obj, &ignored_error);
|
||||
Delete(op_, obj);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace flags_internal
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
#ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
|
||||
#define ABSL_FLAGS_INTERNAL_FLAG_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/flags/internal/commandlineflag.h"
|
||||
#include "absl/flags/internal/registry.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace absl {
|
||||
namespace flags_internal {
|
||||
|
@ -66,51 +69,32 @@ using FlagCallback = void (*)();
|
|||
void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
|
||||
FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu);
|
||||
|
||||
// This is "unspecified" implementation of absl::Flag<T> type.
|
||||
template <typename T>
|
||||
class Flag final : public flags_internal::CommandLineFlag {
|
||||
// The class encapsulates the Flag's data and safe access to it.
|
||||
class FlagImpl {
|
||||
public:
|
||||
constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
|
||||
const char* filename,
|
||||
const flags_internal::FlagMarshallingOpFn marshalling_op,
|
||||
const flags_internal::InitialValGenFunc initial_value_gen)
|
||||
: flags_internal::CommandLineFlag(
|
||||
name, flags_internal::HelpText::FromFunctionPointer(help_gen),
|
||||
filename, &flags_internal::FlagOps<T>, marshalling_op,
|
||||
initial_value_gen,
|
||||
/*def=*/nullptr,
|
||||
/*cur=*/nullptr),
|
||||
atomic_(flags_internal::AtomicInit()),
|
||||
callback_(nullptr) {}
|
||||
constexpr FlagImpl(const flags_internal::FlagOpFn op,
|
||||
const flags_internal::FlagMarshallingOpFn marshalling_op,
|
||||
const flags_internal::InitialValGenFunc initial_value_gen)
|
||||
: op_(op),
|
||||
marshalling_op_(marshalling_op),
|
||||
initial_value_gen_(initial_value_gen) {}
|
||||
|
||||
T Get() const {
|
||||
// Implementation notes:
|
||||
//
|
||||
// We are wrapping a union around the value of `T` to serve three purposes:
|
||||
//
|
||||
// 1. `U.value` has correct size and alignment for a value of type `T`
|
||||
// 2. The `U.value` constructor is not invoked since U's constructor does
|
||||
// not
|
||||
// do it explicitly.
|
||||
// 3. The `U.value` destructor is invoked since U's destructor does it
|
||||
// explicitly. This makes `U` a kind of RAII wrapper around non default
|
||||
// constructible value of T, which is destructed when we leave the
|
||||
// scope. We do need to destroy U.value, which is constructed by
|
||||
// CommandLineFlag::Read even though we left it in a moved-from state
|
||||
// after std::move.
|
||||
//
|
||||
// All of this serves to avoid requiring `T` being default constructible.
|
||||
union U {
|
||||
T value;
|
||||
U() {}
|
||||
~U() { value.~T(); }
|
||||
};
|
||||
U u;
|
||||
|
||||
Read(&u.value, &flags_internal::FlagOps<T>);
|
||||
return std::move(u.value);
|
||||
}
|
||||
// Forces destruction of the Flag's data.
|
||||
void Destroy() const;
|
||||
|
||||
// Constant access methods
|
||||
bool IsModified() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
void Read(const CommandLineFlag& flag, void* dst,
|
||||
const flags_internal::FlagOpFn dst_op) const
|
||||
ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
// Attempts to parse supplied `value` std::string.
|
||||
bool TryParse(const CommandLineFlag& flag, void* dst, absl::string_view value,
|
||||
std::string* err) const
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
|
||||
template <typename T>
|
||||
bool AtomicGet(T* v) const {
|
||||
const int64_t r = atomic_.load(std::memory_order_acquire);
|
||||
if (r != flags_internal::AtomicInit()) {
|
||||
|
@ -121,75 +105,174 @@ class Flag final : public flags_internal::CommandLineFlag {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Set(const T& v) { Write(&v, &flags_internal::FlagOps<T>); }
|
||||
// Mutating access methods
|
||||
void Write(const CommandLineFlag& flag, const void* src,
|
||||
const flags_internal::FlagOpFn src_op)
|
||||
ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
bool SetFromString(const CommandLineFlag& flag, absl::string_view value,
|
||||
FlagSettingMode set_mode, ValueSource source,
|
||||
std::string* err) ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
// If possible, updates copy of the Flag's value that is stored in an
|
||||
// atomic word.
|
||||
void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
|
||||
|
||||
void SetCallback(const flags_internal::FlagCallback mutation_callback) {
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
// Interfaces to operate on callbacks.
|
||||
void SetCallback(const flags_internal::FlagCallback mutation_callback)
|
||||
ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu);
|
||||
|
||||
callback_ = mutation_callback;
|
||||
// Interfaces to save/restore mutable flag data
|
||||
template <typename T>
|
||||
std::unique_ptr<flags_internal::FlagStateInterface> SaveState(
|
||||
Flag<T>* flag) const ABSL_LOCKS_EXCLUDED(locks_->primary_mu) {
|
||||
T&& cur_value = flag->Get();
|
||||
absl::MutexLock l(DataGuard());
|
||||
|
||||
InvokeCallback();
|
||||
return absl::make_unique<flags_internal::FlagState<T>>(
|
||||
flag, std::move(cur_value), modified_, on_command_line_, counter_);
|
||||
}
|
||||
bool RestoreState(const CommandLineFlag& flag, const void* value,
|
||||
bool modified, bool on_command_line, int64_t counter)
|
||||
ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
|
||||
// Value validation interfaces.
|
||||
void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag) const
|
||||
ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
bool ValidateInputValue(absl::string_view value) const
|
||||
ABSL_LOCKS_EXCLUDED(locks_->primary_mu);
|
||||
|
||||
private:
|
||||
friend class FlagState<T>;
|
||||
// Lazy initialization of the Flag's data.
|
||||
void Init();
|
||||
// Ensures that the lazily initialized data is initialized,
|
||||
// and returns pointer to the mutex guarding flags data.
|
||||
absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED(locks_->primary_mu);
|
||||
|
||||
void Destroy() const override {
|
||||
// Values are heap allocated for Abseil Flags.
|
||||
if (cur_) Delete(op_, cur_);
|
||||
if (def_) Delete(op_, def_);
|
||||
// Immutable Flag's data.
|
||||
const FlagOpFn op_; // Type-specific handler
|
||||
const FlagMarshallingOpFn marshalling_op_; // Marshalling ops handler
|
||||
const InitialValGenFunc initial_value_gen_; // Makes flag's initial value
|
||||
|
||||
delete locks_;
|
||||
// Mutable Flag's data. (guarded by locks_->primary_mu).
|
||||
// Indicates that locks_, cur_ and def_ fields have been lazily initialized.
|
||||
std::atomic<bool> inited_{false};
|
||||
// Has flag value been modified?
|
||||
bool modified_ ABSL_GUARDED_BY(locks_->primary_mu) = false;
|
||||
// Specified on command line.
|
||||
bool on_command_line_ ABSL_GUARDED_BY(locks_->primary_mu) = false;
|
||||
// Lazily initialized pointer to default value
|
||||
void* def_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr;
|
||||
// Lazily initialized pointer to current value
|
||||
void* cur_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr;
|
||||
// Mutation counter
|
||||
int64_t counter_ ABSL_GUARDED_BY(locks_->primary_mu) = 0;
|
||||
// For some types, a copy of the current value is kept in an atomically
|
||||
// accessible field.
|
||||
std::atomic<int64_t> atomic_{flags_internal::AtomicInit()};
|
||||
// Mutation callback
|
||||
FlagCallback callback_ = nullptr;
|
||||
|
||||
// Lazily initialized mutexes for this flag value. We cannot inline a
|
||||
// SpinLock or Mutex here because those have non-constexpr constructors and
|
||||
// so would prevent constant initialization of this type.
|
||||
// TODO(rogeeff): fix it once Mutex has constexpr constructor
|
||||
// The following struct contains the locks in a CommandLineFlag struct.
|
||||
// They are in a separate struct that is lazily allocated to avoid problems
|
||||
// with static initialization and to avoid multiple allocations.
|
||||
struct CommandLineFlagLocks {
|
||||
absl::Mutex primary_mu; // protects several fields in CommandLineFlag
|
||||
absl::Mutex callback_mu; // used to serialize callbacks
|
||||
};
|
||||
|
||||
CommandLineFlagLocks* locks_ = nullptr; // locks, laziliy allocated.
|
||||
};
|
||||
|
||||
// This is "unspecified" implementation of absl::Flag<T> type.
|
||||
template <typename T>
|
||||
class Flag final : public flags_internal::CommandLineFlag {
|
||||
public:
|
||||
constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
|
||||
const char* filename,
|
||||
const flags_internal::FlagMarshallingOpFn marshalling_op,
|
||||
const flags_internal::InitialValGenFunc initial_value_gen)
|
||||
: flags_internal::CommandLineFlag(
|
||||
name, flags_internal::HelpText::FromFunctionPointer(help_gen),
|
||||
filename),
|
||||
impl_(&flags_internal::FlagOps<T>, marshalling_op, initial_value_gen) {}
|
||||
|
||||
T Get() const {
|
||||
// See implementation notes in CommandLineFlag::Get().
|
||||
union U {
|
||||
T value;
|
||||
U() {}
|
||||
~U() { value.~T(); }
|
||||
};
|
||||
U u;
|
||||
|
||||
impl_.Read(*this, &u.value, &flags_internal::FlagOps<T>);
|
||||
return std::move(u.value);
|
||||
}
|
||||
|
||||
void StoreAtomic() override {
|
||||
if (sizeof(T) <= sizeof(int64_t)) {
|
||||
int64_t t = 0;
|
||||
std::memcpy(&t, cur_, (std::min)(sizeof(T), sizeof(int64_t)));
|
||||
atomic_.store(t, std::memory_order_release);
|
||||
}
|
||||
bool AtomicGet(T* v) const { return impl_.AtomicGet(v); }
|
||||
|
||||
void Set(const T& v) { impl_.Write(*this, &v, &flags_internal::FlagOps<T>); }
|
||||
|
||||
void SetCallback(const flags_internal::FlagCallback mutation_callback) {
|
||||
impl_.SetCallback(mutation_callback);
|
||||
}
|
||||
|
||||
// CommandLineFlag interface
|
||||
bool IsModified() const override { return impl_.IsModified(); }
|
||||
bool IsSpecifiedOnCommandLine() const override {
|
||||
return impl_.IsSpecifiedOnCommandLine();
|
||||
}
|
||||
std::string DefaultValue() const override { return impl_.DefaultValue(); }
|
||||
std::string CurrentValue() const override { return impl_.CurrentValue(); }
|
||||
|
||||
bool ValidateInputValue(absl::string_view value) const override {
|
||||
return impl_.ValidateInputValue(value);
|
||||
}
|
||||
|
||||
// Interfaces to save and restore flags to/from persistent state.
|
||||
// Returns current flag state or nullptr if flag does not support
|
||||
// saving and restoring a state.
|
||||
std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
|
||||
T curr_value = Get();
|
||||
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
|
||||
return absl::make_unique<flags_internal::FlagState<T>>(
|
||||
this, std::move(curr_value), modified_, on_command_line_, counter_);
|
||||
return impl_.SaveState(this);
|
||||
}
|
||||
|
||||
// Restores the flag state to the supplied state object. If there is
|
||||
// nothing to restore returns false. Otherwise returns true.
|
||||
bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
|
||||
if (MutationCounter() == flag_state.counter_) return false;
|
||||
|
||||
Set(flag_state.cur_value_);
|
||||
|
||||
// Race condition here? This should disappear once we move the rest of the
|
||||
// flag's data into Flag's internals.
|
||||
|
||||
absl::MutexLock l(InitFlagIfNecessary());
|
||||
modified_ = flag_state.modified_;
|
||||
on_command_line_ = flag_state.on_command_line_;
|
||||
return true;
|
||||
return impl_.RestoreState(*this, &flag_state.cur_value_,
|
||||
flag_state.modified_, flag_state.on_command_line_,
|
||||
flag_state.counter_);
|
||||
}
|
||||
|
||||
// Interfaces to overate on callbacks.
|
||||
void InvokeCallback() override
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
|
||||
flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
|
||||
callback_);
|
||||
bool SetFromString(absl::string_view value,
|
||||
flags_internal::FlagSettingMode set_mode,
|
||||
flags_internal::ValueSource source,
|
||||
std::string* error) override {
|
||||
return impl_.SetFromString(*this, value, set_mode, source, error);
|
||||
}
|
||||
|
||||
void CheckDefaultValueParsingRoundtrip() const override {
|
||||
impl_.CheckDefaultValueParsingRoundtrip(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class FlagState<T>;
|
||||
|
||||
void Destroy() const override { impl_.Destroy(); }
|
||||
|
||||
void Read(void* dst) const override {
|
||||
impl_.Read(*this, dst, &flags_internal::FlagOps<T>);
|
||||
}
|
||||
flags_internal::FlagOpFn TypeId() const override {
|
||||
return &flags_internal::FlagOps<T>;
|
||||
}
|
||||
|
||||
// Flag's data
|
||||
// For some types, a copy of the current value is kept in an atomically
|
||||
// accessible field.
|
||||
std::atomic<int64_t> atomic_;
|
||||
FlagCallback callback_; // Mutation callback
|
||||
FlagImpl impl_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -118,7 +118,7 @@ void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
|
|||
(flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
|
||||
"'."),
|
||||
true);
|
||||
} else if (flag->op_ != old_flag->op_) {
|
||||
} else if (flag->TypeId() != old_flag->TypeId()) {
|
||||
flags_internal::ReportUsageError(
|
||||
absl::StrCat("Flag '", flag->Name(),
|
||||
"' was defined more than once but with "
|
||||
|
@ -275,38 +275,49 @@ namespace {
|
|||
|
||||
class RetiredFlagObj final : public flags_internal::CommandLineFlag {
|
||||
public:
|
||||
constexpr RetiredFlagObj(const char* name, FlagOpFn ops,
|
||||
FlagMarshallingOpFn marshalling_ops)
|
||||
constexpr RetiredFlagObj(const char* name, FlagOpFn ops)
|
||||
: flags_internal::CommandLineFlag(
|
||||
name, flags_internal::HelpText::FromStaticCString(nullptr),
|
||||
/*filename=*/"RETIRED", ops, marshalling_ops,
|
||||
/*initial_value_gen=*/nullptr,
|
||||
/*def=*/nullptr,
|
||||
/*cur=*/nullptr) {}
|
||||
/*filename=*/"RETIRED"),
|
||||
op_(ops) {}
|
||||
|
||||
private:
|
||||
bool IsRetired() const override { return true; }
|
||||
|
||||
void Destroy() const override {
|
||||
// Values are heap allocated for Retired Flags.
|
||||
if (cur_) Delete(op_, cur_);
|
||||
if (def_) Delete(op_, def_);
|
||||
|
||||
if (locks_) delete locks_;
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
flags_internal::FlagOpFn TypeId() const override { return op_; }
|
||||
bool IsRetired() const override { return true; }
|
||||
bool IsModified() const override { return false; }
|
||||
bool IsSpecifiedOnCommandLine() const override { return false; }
|
||||
std::string DefaultValue() const override { return ""; }
|
||||
std::string CurrentValue() const override { return ""; }
|
||||
|
||||
// Any input is valid
|
||||
bool ValidateInputValue(absl::string_view) const override { return true; }
|
||||
|
||||
std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SetFromString(absl::string_view, flags_internal::FlagSettingMode,
|
||||
flags_internal::ValueSource, std::string*) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void CheckDefaultValueParsingRoundtrip() const override {}
|
||||
|
||||
void Read(void*) const override {}
|
||||
|
||||
// Data members
|
||||
const FlagOpFn op_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Retire(const char* name, FlagOpFn ops,
|
||||
FlagMarshallingOpFn marshalling_ops) {
|
||||
auto* flag = new flags_internal::RetiredFlagObj(name, ops, marshalling_ops);
|
||||
bool Retire(const char* name, FlagOpFn ops) {
|
||||
auto* flag = new flags_internal::RetiredFlagObj(name, ops);
|
||||
FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -76,14 +76,12 @@ bool RegisterCommandLineFlag(CommandLineFlag*);
|
|||
//
|
||||
|
||||
// Retire flag with name "name" and type indicated by ops.
|
||||
bool Retire(const char* name, FlagOpFn ops,
|
||||
FlagMarshallingOpFn marshalling_ops);
|
||||
bool Retire(const char* name, FlagOpFn ops);
|
||||
|
||||
// Registered a retired flag with name 'flag_name' and type 'T'.
|
||||
template <typename T>
|
||||
inline bool RetiredFlag(const char* flag_name) {
|
||||
return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>,
|
||||
flags_internal::FlagMarshallingOps<T>);
|
||||
return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>);
|
||||
}
|
||||
|
||||
// If the flag is retired, returns true and indicates in |*type_is_bool|
|
||||
|
|
|
@ -196,8 +196,8 @@ TEST(IOStreamStateSaver, RoundTripFloats) {
|
|||
EXPECT_EQ(-d, StreamRoundTrip<double>(-d));
|
||||
|
||||
// Avoid undefined behavior (overflow/underflow).
|
||||
if (d <= std::numeric_limits<int64_t>::max() &&
|
||||
d >= std::numeric_limits<int64_t>::lowest()) {
|
||||
if (f <= static_cast<float>(std::numeric_limits<int64_t>::max()) &&
|
||||
f >= static_cast<float>(std::numeric_limits<int64_t>::lowest())) {
|
||||
int64_t x = static_cast<int64_t>(f);
|
||||
EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
|
||||
}
|
||||
|
@ -264,8 +264,8 @@ TEST(IOStreamStateSaver, RoundTripDoubles) {
|
|||
}
|
||||
|
||||
// Avoid undefined behavior (overflow/underflow).
|
||||
if (d <= std::numeric_limits<int64_t>::max() &&
|
||||
d >= std::numeric_limits<int64_t>::lowest()) {
|
||||
if (d <= static_cast<double>(std::numeric_limits<int64_t>::max()) &&
|
||||
d >= static_cast<double>(std::numeric_limits<int64_t>::lowest())) {
|
||||
int64_t x = static_cast<int64_t>(d);
|
||||
EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
|
||||
}
|
||||
|
|
|
@ -35,8 +35,7 @@ struct ResizeUninitializedTraits {
|
|||
static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
|
||||
};
|
||||
|
||||
// __resize_default_init is provided by libc++ >= 8.0 and by Google's internal
|
||||
// ::string implementation.
|
||||
// __resize_default_init is provided by libc++ >= 8.0
|
||||
template <typename string_type>
|
||||
struct ResizeUninitializedTraits<
|
||||
string_type, absl::void_t<decltype(std::declval<string_type&>()
|
||||
|
|
|
@ -28,6 +28,5 @@ time docker run \
|
|||
--rm \
|
||||
-e CFLAGS="-Werror" \
|
||||
-e CXXFLAGS="-Werror" \
|
||||
gcr.io/google.com/absl-177019/linux_gcc-latest:20190703 \
|
||||
gcr.io/google.com/absl-177019/linux_gcc-latest:20191018 \
|
||||
/bin/bash CMake/install_test_project/test.sh $@
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
|||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||
fi
|
||||
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
|
||||
|
||||
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||
# Without access to the credentials this won't work.
|
||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
|||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||
fi
|
||||
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
|
||||
|
||||
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||
# Without access to the credentials this won't work.
|
||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
|||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||
fi
|
||||
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
|
||||
|
||||
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||
# Without access to the credentials this won't work.
|
||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
|||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||
fi
|
||||
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20191018"
|
||||
|
||||
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||
# Without access to the credentials this won't work.
|
||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
|||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||
fi
|
||||
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20190702"
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
|
||||
|
||||
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||
# Without access to the credentials this won't work.
|
||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
|||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||
fi
|
||||
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20190703"
|
||||
readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20191018"
|
||||
|
||||
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||
# Without access to the credentials this won't work.
|
||||
|
|
|
@ -47,7 +47,7 @@ for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
|
|||
--rm \
|
||||
-e CFLAGS="-Werror" \
|
||||
-e CXXFLAGS="-Werror" \
|
||||
gcr.io/google.com/absl-177019/linux_gcc-latest:20190703 \
|
||||
gcr.io/google.com/absl-177019/linux_gcc-latest:20191018 \
|
||||
/bin/bash -c "
|
||||
cd /buildfs && \
|
||||
cmake /abseil-cpp \
|
||||
|
|
Loading…
Reference in a new issue