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.
|
// List of builtin types from Itanium C++ ABI.
|
||||||
|
//
|
||||||
|
// Invariant: only one- or two-character type abbreviations here.
|
||||||
static const AbbrevPair kBuiltinTypeList[] = {
|
static const AbbrevPair kBuiltinTypeList[] = {
|
||||||
{"v", "void", 0},
|
{"v", "void", 0},
|
||||||
{"w", "wchar_t", 0},
|
{"w", "wchar_t", 0},
|
||||||
|
@ -115,6 +117,16 @@ static const AbbrevPair kBuiltinTypeList[] = {
|
||||||
{"e", "long double", 0},
|
{"e", "long double", 0},
|
||||||
{"g", "__float128", 0},
|
{"g", "__float128", 0},
|
||||||
{"z", "ellipsis", 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},
|
{nullptr, nullptr, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1168,12 +1180,6 @@ static bool ParseType(State *state) {
|
||||||
}
|
}
|
||||||
state->parse_state = copy;
|
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) &&
|
if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
|
||||||
ParseType(state)) {
|
ParseType(state)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1214,16 +1220,26 @@ static bool ParseCVQualifiers(State *state) {
|
||||||
return num_cv_qualifiers > 0;
|
return num_cv_qualifiers > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// <builtin-type> ::= v, etc.
|
// <builtin-type> ::= v, etc. # single-character builtin types
|
||||||
// ::= u <source-name>
|
// ::= u <source-name>
|
||||||
|
// ::= Dd, etc. # two-character builtin types
|
||||||
|
//
|
||||||
|
// Not supported:
|
||||||
|
// ::= DF <number> _ # _FloatN (N bits)
|
||||||
|
//
|
||||||
static bool ParseBuiltinType(State *state) {
|
static bool ParseBuiltinType(State *state) {
|
||||||
ComplexityGuard guard(state);
|
ComplexityGuard guard(state);
|
||||||
if (guard.IsTooComplex()) return false;
|
if (guard.IsTooComplex()) return false;
|
||||||
const AbbrevPair *p;
|
const AbbrevPair *p;
|
||||||
for (p = kBuiltinTypeList; p->abbrev != nullptr; ++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);
|
MaybeAppend(state, p->real_name);
|
||||||
++state->parse_state.mangled_idx;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,10 @@ namespace absl {
|
||||||
// GetStackFrames()
|
// GetStackFrames()
|
||||||
//
|
//
|
||||||
// Records program counter values for up to `max_depth` frames, skipping the
|
// Records program counter values for up to `max_depth` frames, skipping the
|
||||||
// most recent `skip_count` stack frames, and stores their corresponding values
|
// most recent `skip_count` stack frames, stores their corresponding values
|
||||||
// and sizes in `results` and `sizes` buffers. (Note that the frame generated
|
// and sizes in `results` and `sizes` buffers, and returns the number of frames
|
||||||
// for the `absl::GetStackFrames()` routine itself is also skipped.)
|
// stored. (Note that the frame generated for the `absl::GetStackFrames()`
|
||||||
// routine itself.
|
// routine itself is also skipped.)
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
|
@ -54,8 +54,8 @@ namespace absl {
|
||||||
// The current stack frame would consist of three function calls: `bar()`,
|
// The current stack frame would consist of three function calls: `bar()`,
|
||||||
// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
|
// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
|
||||||
// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently
|
// `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
|
// invoked function call. It will therefore return 2 and fill `result` with
|
||||||
// produce values that map to the following function calls:
|
// program counters within the following functions:
|
||||||
//
|
//
|
||||||
// result[0] foo()
|
// result[0] foo()
|
||||||
// result[1] main()
|
// 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
|
// Records program counter values obtained from a signal handler. Records
|
||||||
// program counter values for up to `max_depth` frames, skipping the most recent
|
// 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
|
// `skip_count` stack frames, stores their corresponding values and sizes in
|
||||||
// `results` and `sizes` buffers. (Note that the frame generated for the
|
// `results` and `sizes` buffers, and returns the number of frames stored. (Note
|
||||||
// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
// 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
|
// 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
|
// 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()
|
// GetStackTrace()
|
||||||
//
|
//
|
||||||
// Records program counter values for up to `max_depth` frames, skipping the
|
// Records program counter values for up to `max_depth` frames, skipping the
|
||||||
// most recent `skip_count` stack frames, and stores their corresponding values
|
// most recent `skip_count` stack frames, stores their corresponding values
|
||||||
// in `results`. Note that this function is similar to `absl::GetStackFrames()`
|
// 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.
|
// except that it returns the stack trace only, and not stack frame sizes.
|
||||||
//
|
//
|
||||||
// Example:
|
// 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
|
// Records program counter values obtained from a signal handler. Records
|
||||||
// program counter values for up to `max_depth` frames, skipping the most recent
|
// program counter values for up to `max_depth` frames, skipping the most recent
|
||||||
// `skip_count` stack frames, and stores their corresponding values in
|
// `skip_count` stack frames, stores their corresponding values in `results`,
|
||||||
// `results`. (Note that the frame generated for the
|
// and returns the number of frames stored. (Note that the frame generated for
|
||||||
// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
// the `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
||||||
//
|
//
|
||||||
// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
|
// 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
|
// passed to a signal handler registered via the `sa_sigaction` field of a
|
||||||
|
|
|
@ -40,6 +40,7 @@ cc_library(
|
||||||
deps = [
|
deps = [
|
||||||
":handle",
|
":handle",
|
||||||
":registry",
|
":registry",
|
||||||
|
"//absl/base:core_headers",
|
||||||
"//absl/memory",
|
"//absl/memory",
|
||||||
"//absl/strings",
|
"//absl/strings",
|
||||||
"//absl/synchronization",
|
"//absl/synchronization",
|
||||||
|
@ -135,9 +136,6 @@ cc_library(
|
||||||
":config",
|
":config",
|
||||||
":marshalling",
|
":marshalling",
|
||||||
"//absl/base:core_headers",
|
"//absl/base:core_headers",
|
||||||
"//absl/base:raw_logging_internal",
|
|
||||||
"//absl/strings",
|
|
||||||
"//absl/synchronization",
|
|
||||||
"//absl/types:optional",
|
"//absl/types:optional",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Flag;
|
||||||
// Flag
|
// Flag
|
||||||
//
|
//
|
||||||
// Forward declaration of the `absl::Flag` type for use in defining the macro.
|
// 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>
|
template <typename T>
|
||||||
class Flag;
|
class Flag;
|
||||||
#else
|
#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
|
// This global nutex protects on-demand construction of flag objects in MSVC
|
||||||
// builds.
|
// builds.
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
|
||||||
namespace flags_internal {
|
namespace flags_internal {
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace absl {
|
||||||
// ABSL_FLAG(int, count, 0, "Count of items to process");
|
// ABSL_FLAG(int, count, 0, "Count of items to process");
|
||||||
//
|
//
|
||||||
// No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
|
// 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>
|
template <typename T>
|
||||||
using Flag = flags_internal::Flag<T>;
|
using Flag = flags_internal::Flag<T>;
|
||||||
#else
|
#else
|
||||||
|
@ -119,7 +119,6 @@ class Flag {
|
||||||
absl::string_view Name() const { return GetImpl()->Name(); }
|
absl::string_view Name() const { return GetImpl()->Name(); }
|
||||||
std::string Help() const { return GetImpl()->Help(); }
|
std::string Help() const { return GetImpl()->Help(); }
|
||||||
bool IsModified() const { return GetImpl()->IsModified(); }
|
bool IsModified() const { return GetImpl()->IsModified(); }
|
||||||
void SetModified(bool is_modified) { GetImpl()->SetModified(is_modified); }
|
|
||||||
bool IsSpecifiedOnCommandLine() const {
|
bool IsSpecifiedOnCommandLine() const {
|
||||||
return GetImpl()->IsSpecifiedOnCommandLine();
|
return GetImpl()->IsSpecifiedOnCommandLine();
|
||||||
}
|
}
|
||||||
|
@ -127,9 +126,6 @@ class Flag {
|
||||||
std::string Filename() const { return GetImpl()->Filename(); }
|
std::string Filename() const { return GetImpl()->Filename(); }
|
||||||
std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
|
std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
|
||||||
std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
|
std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
|
||||||
bool InvokeValidator(const void* value) const {
|
|
||||||
return GetImpl()->InvokeValidator(value);
|
|
||||||
}
|
|
||||||
template <typename T1>
|
template <typename T1>
|
||||||
inline bool IsOfType() const {
|
inline bool IsOfType() const {
|
||||||
return GetImpl()->template IsOfType<T1>();
|
return GetImpl()->template IsOfType<T1>();
|
||||||
|
@ -272,7 +268,7 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
|
||||||
#if ABSL_FLAGS_STRIP_NAMES
|
#if ABSL_FLAGS_STRIP_NAMES
|
||||||
#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
|
#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
|
||||||
#define ABSL_FLAG_IMPL_FILENAME() ""
|
#define ABSL_FLAG_IMPL_FILENAME() ""
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER) || defined(__clang__)
|
||||||
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
||||||
absl::flags_internal::FlagRegistrar<T, false>(&flag)
|
absl::flags_internal::FlagRegistrar<T, false>(&flag)
|
||||||
#else
|
#else
|
||||||
|
@ -282,7 +278,7 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
|
||||||
#else
|
#else
|
||||||
#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
|
#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
|
||||||
#define ABSL_FLAG_IMPL_FILENAME() __FILE__
|
#define ABSL_FLAG_IMPL_FILENAME() __FILE__
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER) || defined(__clang__)
|
||||||
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
|
||||||
absl::flags_internal::FlagRegistrar<T, true>(&flag)
|
absl::flags_internal::FlagRegistrar<T, true>(&flag)
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -42,15 +42,14 @@ void TestCallback() {}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool TestConstructionFor() {
|
bool TestConstructionFor() {
|
||||||
constexpr flags::Flag<T> f1("f1", &TestHelpMsg, "file",
|
constexpr flags::Flag<T> f1("f1", &TestHelpMsg, "file",
|
||||||
&absl::flags_internal::FlagMarshallingOps<T>,
|
&flags::FlagMarshallingOps<T>, &TestMakeDflt<T>);
|
||||||
&TestMakeDflt<T>);
|
|
||||||
EXPECT_EQ(f1.Name(), "f1");
|
EXPECT_EQ(f1.Name(), "f1");
|
||||||
EXPECT_EQ(f1.Help(), "help");
|
EXPECT_EQ(f1.Help(), "help");
|
||||||
EXPECT_EQ(f1.Filename(), "file");
|
EXPECT_EQ(f1.Filename(), "file");
|
||||||
|
|
||||||
ABSL_CONST_INIT static flags::Flag<T> f2(
|
ABSL_CONST_INIT static flags::Flag<T> f2("f2", &TestHelpMsg, "file",
|
||||||
"f2", &TestHelpMsg, "file", &absl::flags_internal::FlagMarshallingOps<T>,
|
&flags::FlagMarshallingOps<T>,
|
||||||
&TestMakeDflt<T>);
|
&TestMakeDflt<T>);
|
||||||
flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
|
flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
|
||||||
|
|
||||||
EXPECT_EQ(f2.Name(), "f2");
|
EXPECT_EQ(f2.Name(), "f2");
|
||||||
|
|
|
@ -15,14 +15,7 @@
|
||||||
|
|
||||||
#include "absl/flags/internal/commandlineflag.h"
|
#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/flags/usage_config.h"
|
||||||
#include "absl/strings/str_cat.h"
|
|
||||||
#include "absl/synchronization/mutex.h"
|
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace flags_internal {
|
namespace flags_internal {
|
||||||
|
@ -35,80 +28,6 @@ namespace flags_internal {
|
||||||
// This is used by this file, and also in commandlineflags_reporting.cc
|
// This is used by this file, and also in commandlineflags_reporting.cc
|
||||||
const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
|
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 {
|
absl::string_view CommandLineFlag::Typename() const {
|
||||||
// We do not store/report type in Abseil Flags, so that user do not rely on in
|
// We do not store/report type in Abseil Flags, so that user do not rely on in
|
||||||
// at runtime
|
// at runtime
|
||||||
|
@ -137,223 +56,6 @@ std::string CommandLineFlag::Filename() const {
|
||||||
return flags_internal::GetUsageConfig().normalize_filename(filename_);
|
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 {
|
std::string HelpText::GetHelpText() const {
|
||||||
if (help_function_) return help_function_();
|
if (help_function_) return help_function_();
|
||||||
if (help_message_) return help_message_;
|
if (help_message_) return help_message_;
|
||||||
|
@ -361,40 +63,5 @@ std::string HelpText::GetHelpText() const {
|
||||||
return {};
|
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 flags_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
|
@ -16,12 +16,10 @@
|
||||||
#ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
#ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
||||||
#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "absl/base/macros.h"
|
#include "absl/base/macros.h"
|
||||||
#include "absl/flags/marshalling.h"
|
#include "absl/flags/marshalling.h"
|
||||||
#include "absl/synchronization/mutex.h"
|
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
|
@ -151,14 +149,6 @@ inline size_t Sizeof(FlagOpFn op) {
|
||||||
op(flags_internal::kSizeof, nullptr, nullptr)));
|
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
|
// 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
|
// needed for supporting both static initialization of Flags while supporting
|
||||||
// the legacy registration framework. We can't use absl::variant<const char*,
|
// the legacy registration framework. We can't use absl::variant<const char*,
|
||||||
|
@ -200,25 +190,9 @@ class FlagStateInterface {
|
||||||
// Holds all information for a flag.
|
// Holds all information for a flag.
|
||||||
class CommandLineFlag {
|
class CommandLineFlag {
|
||||||
public:
|
public:
|
||||||
constexpr CommandLineFlag(
|
constexpr CommandLineFlag(const char* name, HelpText help_text,
|
||||||
const char* name, HelpText help_text, const char* filename,
|
const char* filename)
|
||||||
const flags_internal::FlagOpFn op,
|
: name_(name), help_(help_text), filename_(filename) {}
|
||||||
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) {}
|
|
||||||
|
|
||||||
// Virtual destructor
|
// Virtual destructor
|
||||||
virtual void Destroy() const = 0;
|
virtual void Destroy() const = 0;
|
||||||
|
@ -227,60 +201,73 @@ class CommandLineFlag {
|
||||||
CommandLineFlag(const CommandLineFlag&) = delete;
|
CommandLineFlag(const CommandLineFlag&) = delete;
|
||||||
CommandLineFlag& operator=(const CommandLineFlag&) = delete;
|
CommandLineFlag& operator=(const CommandLineFlag&) = delete;
|
||||||
|
|
||||||
// Access methods.
|
// Non-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; }
|
|
||||||
|
|
||||||
absl::string_view Name() const { return name_; }
|
absl::string_view Name() const { return name_; }
|
||||||
std::string Help() const { return help_.GetHelpText(); }
|
std::string Help() const { return help_.GetHelpText(); }
|
||||||
bool IsModified() const;
|
|
||||||
void SetModified(bool is_modified);
|
|
||||||
bool IsSpecifiedOnCommandLine() const;
|
|
||||||
|
|
||||||
absl::string_view Typename() const;
|
absl::string_view Typename() const;
|
||||||
std::string Filename() 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.
|
// Return true iff flag has type T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool IsOfType() const {
|
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,
|
// Attempts to retrieve the flag value. Returns value on success,
|
||||||
// absl::nullopt otherwise.
|
// absl::nullopt otherwise.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
absl::optional<T> Get() const {
|
absl::optional<T> Get() const {
|
||||||
if (IsRetired() || flags_internal::FlagOps<T> != op_) return absl::nullopt;
|
if (IsRetired() || !IsOfType<T>()) {
|
||||||
|
return absl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
T res;
|
// Implementation notes:
|
||||||
Read(&res, flags_internal::FlagOps<T>);
|
//
|
||||||
|
// 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
|
// Interface to save flag to some persistent state. Returns current flag state
|
||||||
// or nullptr if flag does not support saving and restoring a state.
|
// or nullptr if flag does not support saving and restoring a state.
|
||||||
virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
|
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
|
// 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`
|
// was successfully set to new value, it returns true. Otherwise, sets `error`
|
||||||
// to indicate the error, leaves the flag unchanged, and returns false. There
|
// 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 flag's default value
|
||||||
// * Update the current flag value if it was never set before
|
// * Update the current flag value if it was never set before
|
||||||
// The mode is selected based on `set_mode` parameter.
|
// The mode is selected based on `set_mode` parameter.
|
||||||
bool SetFromString(absl::string_view value,
|
virtual bool SetFromString(absl::string_view value,
|
||||||
flags_internal::FlagSettingMode set_mode,
|
flags_internal::FlagSettingMode set_mode,
|
||||||
flags_internal::ValueSource source, std::string* error);
|
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.
|
// Constant configuration for a particular flag.
|
||||||
protected:
|
protected:
|
||||||
~CommandLineFlag() = default;
|
~CommandLineFlag() = default;
|
||||||
|
|
||||||
// Thread safe access to mutation counter.
|
const char* const name_; // Flags name passed to ABSL_FLAG as second arg.
|
||||||
int64_t MutationCounter() const;
|
const HelpText help_; // The function generating help message.
|
||||||
|
const char* const filename_; // The file name where ABSL_FLAG resides.
|
||||||
|
|
||||||
const char* const name_;
|
private:
|
||||||
const HelpText help_;
|
// Copy-construct a new value of the flag's type in a memory referenced by
|
||||||
const char* const filename_;
|
// the dst based on the current flag's value.
|
||||||
|
virtual void Read(void* dst) const = 0;
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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
|
// 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,
|
// 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
|
// 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/flags/internal/flag.h"
|
||||||
|
|
||||||
|
#include "absl/base/optimization.h"
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace flags_internal {
|
namespace flags_internal {
|
||||||
|
namespace {
|
||||||
|
|
||||||
// If the flag has a mutation callback this function invokes it. While the
|
// Currently we only validate flag values for user-defined flag types.
|
||||||
// callback is being invoked the primary flag's mutex is unlocked and it is
|
bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
|
||||||
// re-locked back after call to callback is completed. Callback invocation is
|
#define DONT_VALIDATE(T) \
|
||||||
// guarded by flag's secondary mutex instead which prevents concurrent
|
if (flag.IsOfType<T>()) return false;
|
||||||
// callback invocation. Note that it is possible for other thread to grab the
|
ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
|
||||||
// primary lock and update flag's value at any time during the callback
|
DONT_VALIDATE(std::string)
|
||||||
// invocation. This is by design. Callback can get a value of the flag if
|
DONT_VALIDATE(std::vector<std::string>)
|
||||||
// necessary, but it might be different from the value initiated the callback
|
#undef DONT_VALIDATE
|
||||||
// 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;
|
|
||||||
|
|
||||||
// When executing the callback we need the primary flag's mutex to be
|
return true;
|
||||||
// unlocked so that callback can retrieve the flag's value.
|
}
|
||||||
primary_mu->Unlock();
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void FlagImpl::Init() {
|
||||||
|
ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
|
||||||
|
|
||||||
{
|
{
|
||||||
absl::MutexLock lock(callback_mu);
|
absl::MutexLock lock(&init_lock);
|
||||||
cb();
|
|
||||||
|
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
|
} // namespace flags_internal
|
||||||
|
|
|
@ -16,12 +16,15 @@
|
||||||
#ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
|
#ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
|
||||||
#define ABSL_FLAGS_INTERNAL_FLAG_H_
|
#define ABSL_FLAGS_INTERNAL_FLAG_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "absl/base/thread_annotations.h"
|
||||||
#include "absl/flags/internal/commandlineflag.h"
|
#include "absl/flags/internal/commandlineflag.h"
|
||||||
#include "absl/flags/internal/registry.h"
|
#include "absl/flags/internal/registry.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
|
#include "absl/synchronization/mutex.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace flags_internal {
|
namespace flags_internal {
|
||||||
|
@ -66,51 +69,32 @@ using FlagCallback = void (*)();
|
||||||
void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
|
void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
|
||||||
FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu);
|
FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu);
|
||||||
|
|
||||||
// This is "unspecified" implementation of absl::Flag<T> type.
|
// The class encapsulates the Flag's data and safe access to it.
|
||||||
template <typename T>
|
class FlagImpl {
|
||||||
class Flag final : public flags_internal::CommandLineFlag {
|
|
||||||
public:
|
public:
|
||||||
constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
|
constexpr FlagImpl(const flags_internal::FlagOpFn op,
|
||||||
const char* filename,
|
const flags_internal::FlagMarshallingOpFn marshalling_op,
|
||||||
const flags_internal::FlagMarshallingOpFn marshalling_op,
|
const flags_internal::InitialValGenFunc initial_value_gen)
|
||||||
const flags_internal::InitialValGenFunc initial_value_gen)
|
: op_(op),
|
||||||
: flags_internal::CommandLineFlag(
|
marshalling_op_(marshalling_op),
|
||||||
name, flags_internal::HelpText::FromFunctionPointer(help_gen),
|
initial_value_gen_(initial_value_gen) {}
|
||||||
filename, &flags_internal::FlagOps<T>, marshalling_op,
|
|
||||||
initial_value_gen,
|
|
||||||
/*def=*/nullptr,
|
|
||||||
/*cur=*/nullptr),
|
|
||||||
atomic_(flags_internal::AtomicInit()),
|
|
||||||
callback_(nullptr) {}
|
|
||||||
|
|
||||||
T Get() const {
|
// Forces destruction of the Flag's data.
|
||||||
// Implementation notes:
|
void Destroy() const;
|
||||||
//
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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 {
|
bool AtomicGet(T* v) const {
|
||||||
const int64_t r = atomic_.load(std::memory_order_acquire);
|
const int64_t r = atomic_.load(std::memory_order_acquire);
|
||||||
if (r != flags_internal::AtomicInit()) {
|
if (r != flags_internal::AtomicInit()) {
|
||||||
|
@ -121,75 +105,174 @@ class Flag final : public flags_internal::CommandLineFlag {
|
||||||
return false;
|
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) {
|
// Interfaces to operate on callbacks.
|
||||||
absl::MutexLock l(InitFlagIfNecessary());
|
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:
|
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 {
|
// Immutable Flag's data.
|
||||||
// Values are heap allocated for Abseil Flags.
|
const FlagOpFn op_; // Type-specific handler
|
||||||
if (cur_) Delete(op_, cur_);
|
const FlagMarshallingOpFn marshalling_op_; // Marshalling ops handler
|
||||||
if (def_) Delete(op_, def_);
|
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 {
|
bool AtomicGet(T* v) const { return impl_.AtomicGet(v); }
|
||||||
if (sizeof(T) <= sizeof(int64_t)) {
|
|
||||||
int64_t t = 0;
|
void Set(const T& v) { impl_.Write(*this, &v, &flags_internal::FlagOps<T>); }
|
||||||
std::memcpy(&t, cur_, (std::min)(sizeof(T), sizeof(int64_t)));
|
|
||||||
atomic_.store(t, std::memory_order_release);
|
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.
|
// Interfaces to save and restore flags to/from persistent state.
|
||||||
// Returns current flag state or nullptr if flag does not support
|
// Returns current flag state or nullptr if flag does not support
|
||||||
// saving and restoring a state.
|
// saving and restoring a state.
|
||||||
std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
|
std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
|
||||||
T curr_value = Get();
|
return impl_.SaveState(this);
|
||||||
|
|
||||||
absl::MutexLock l(InitFlagIfNecessary());
|
|
||||||
|
|
||||||
return absl::make_unique<flags_internal::FlagState<T>>(
|
|
||||||
this, std::move(curr_value), modified_, on_command_line_, counter_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restores the flag state to the supplied state object. If there is
|
// Restores the flag state to the supplied state object. If there is
|
||||||
// nothing to restore returns false. Otherwise returns true.
|
// nothing to restore returns false. Otherwise returns true.
|
||||||
bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
|
bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
|
||||||
if (MutationCounter() == flag_state.counter_) return false;
|
return impl_.RestoreState(*this, &flag_state.cur_value_,
|
||||||
|
flag_state.modified_, flag_state.on_command_line_,
|
||||||
Set(flag_state.cur_value_);
|
flag_state.counter_);
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interfaces to overate on callbacks.
|
bool SetFromString(absl::string_view value,
|
||||||
void InvokeCallback() override
|
flags_internal::FlagSettingMode set_mode,
|
||||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
|
flags_internal::ValueSource source,
|
||||||
flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
|
std::string* error) override {
|
||||||
callback_);
|
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
|
// Flag's data
|
||||||
// For some types, a copy of the current value is kept in an atomically
|
FlagImpl impl_;
|
||||||
// accessible field.
|
|
||||||
std::atomic<int64_t> atomic_;
|
|
||||||
FlagCallback callback_; // Mutation callback
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -118,7 +118,7 @@ void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
|
||||||
(flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
|
(flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
|
||||||
"'."),
|
"'."),
|
||||||
true);
|
true);
|
||||||
} else if (flag->op_ != old_flag->op_) {
|
} else if (flag->TypeId() != old_flag->TypeId()) {
|
||||||
flags_internal::ReportUsageError(
|
flags_internal::ReportUsageError(
|
||||||
absl::StrCat("Flag '", flag->Name(),
|
absl::StrCat("Flag '", flag->Name(),
|
||||||
"' was defined more than once but with "
|
"' was defined more than once but with "
|
||||||
|
@ -275,38 +275,49 @@ namespace {
|
||||||
|
|
||||||
class RetiredFlagObj final : public flags_internal::CommandLineFlag {
|
class RetiredFlagObj final : public flags_internal::CommandLineFlag {
|
||||||
public:
|
public:
|
||||||
constexpr RetiredFlagObj(const char* name, FlagOpFn ops,
|
constexpr RetiredFlagObj(const char* name, FlagOpFn ops)
|
||||||
FlagMarshallingOpFn marshalling_ops)
|
|
||||||
: flags_internal::CommandLineFlag(
|
: flags_internal::CommandLineFlag(
|
||||||
name, flags_internal::HelpText::FromStaticCString(nullptr),
|
name, flags_internal::HelpText::FromStaticCString(nullptr),
|
||||||
/*filename=*/"RETIRED", ops, marshalling_ops,
|
/*filename=*/"RETIRED"),
|
||||||
/*initial_value_gen=*/nullptr,
|
op_(ops) {}
|
||||||
/*def=*/nullptr,
|
|
||||||
/*cur=*/nullptr) {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool IsRetired() const override { return true; }
|
|
||||||
|
|
||||||
void Destroy() const override {
|
void Destroy() const override {
|
||||||
// Values are heap allocated for Retired Flags.
|
// Values are heap allocated for Retired Flags.
|
||||||
if (cur_) Delete(op_, cur_);
|
|
||||||
if (def_) Delete(op_, def_);
|
|
||||||
|
|
||||||
if (locks_) delete locks_;
|
|
||||||
|
|
||||||
delete this;
|
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 {
|
std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
|
||||||
return nullptr;
|
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
|
} // namespace
|
||||||
|
|
||||||
bool Retire(const char* name, FlagOpFn ops,
|
bool Retire(const char* name, FlagOpFn ops) {
|
||||||
FlagMarshallingOpFn marshalling_ops) {
|
auto* flag = new flags_internal::RetiredFlagObj(name, ops);
|
||||||
auto* flag = new flags_internal::RetiredFlagObj(name, ops, marshalling_ops);
|
|
||||||
FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
|
FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,14 +76,12 @@ bool RegisterCommandLineFlag(CommandLineFlag*);
|
||||||
//
|
//
|
||||||
|
|
||||||
// Retire flag with name "name" and type indicated by ops.
|
// Retire flag with name "name" and type indicated by ops.
|
||||||
bool Retire(const char* name, FlagOpFn ops,
|
bool Retire(const char* name, FlagOpFn ops);
|
||||||
FlagMarshallingOpFn marshalling_ops);
|
|
||||||
|
|
||||||
// Registered a retired flag with name 'flag_name' and type 'T'.
|
// Registered a retired flag with name 'flag_name' and type 'T'.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool RetiredFlag(const char* flag_name) {
|
inline bool RetiredFlag(const char* flag_name) {
|
||||||
return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>,
|
return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>);
|
||||||
flags_internal::FlagMarshallingOps<T>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the flag is retired, returns true and indicates in |*type_is_bool|
|
// 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));
|
EXPECT_EQ(-d, StreamRoundTrip<double>(-d));
|
||||||
|
|
||||||
// Avoid undefined behavior (overflow/underflow).
|
// Avoid undefined behavior (overflow/underflow).
|
||||||
if (d <= std::numeric_limits<int64_t>::max() &&
|
if (f <= static_cast<float>(std::numeric_limits<int64_t>::max()) &&
|
||||||
d >= std::numeric_limits<int64_t>::lowest()) {
|
f >= static_cast<float>(std::numeric_limits<int64_t>::lowest())) {
|
||||||
int64_t x = static_cast<int64_t>(f);
|
int64_t x = static_cast<int64_t>(f);
|
||||||
EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
|
EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
|
||||||
}
|
}
|
||||||
|
@ -264,8 +264,8 @@ TEST(IOStreamStateSaver, RoundTripDoubles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid undefined behavior (overflow/underflow).
|
// Avoid undefined behavior (overflow/underflow).
|
||||||
if (d <= std::numeric_limits<int64_t>::max() &&
|
if (d <= static_cast<double>(std::numeric_limits<int64_t>::max()) &&
|
||||||
d >= std::numeric_limits<int64_t>::lowest()) {
|
d >= static_cast<double>(std::numeric_limits<int64_t>::lowest())) {
|
||||||
int64_t x = static_cast<int64_t>(d);
|
int64_t x = static_cast<int64_t>(d);
|
||||||
EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
|
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); }
|
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
|
// __resize_default_init is provided by libc++ >= 8.0
|
||||||
// ::string implementation.
|
|
||||||
template <typename string_type>
|
template <typename string_type>
|
||||||
struct ResizeUninitializedTraits<
|
struct ResizeUninitializedTraits<
|
||||||
string_type, absl::void_t<decltype(std::declval<string_type&>()
|
string_type, absl::void_t<decltype(std::declval<string_type&>()
|
||||||
|
|
|
@ -28,6 +28,5 @@ time docker run \
|
||||||
--rm \
|
--rm \
|
||||||
-e CFLAGS="-Werror" \
|
-e CFLAGS="-Werror" \
|
||||||
-e CXXFLAGS="-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 $@
|
/bin/bash CMake/install_test_project/test.sh $@
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
||||||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||||
fi
|
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.
|
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||||
# Without access to the credentials this won't work.
|
# Without access to the credentials this won't work.
|
||||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
||||||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||||
fi
|
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.
|
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||||
# Without access to the credentials this won't work.
|
# Without access to the credentials this won't work.
|
||||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
||||||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||||
fi
|
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.
|
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||||
# Without access to the credentials this won't work.
|
# Without access to the credentials this won't work.
|
||||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
||||||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||||
fi
|
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.
|
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||||
# Without access to the credentials this won't work.
|
# Without access to the credentials this won't work.
|
||||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
||||||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||||
fi
|
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.
|
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||||
# Without access to the credentials this won't work.
|
# Without access to the credentials this won't work.
|
||||||
|
|
|
@ -36,7 +36,7 @@ if [ -z ${EXCEPTIONS_MODE:-} ]; then
|
||||||
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
|
||||||
fi
|
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.
|
# USE_BAZEL_CACHE=1 only works on Kokoro.
|
||||||
# Without access to the credentials this won't work.
|
# Without access to the credentials this won't work.
|
||||||
|
|
|
@ -47,7 +47,7 @@ for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
|
||||||
--rm \
|
--rm \
|
||||||
-e CFLAGS="-Werror" \
|
-e CFLAGS="-Werror" \
|
||||||
-e CXXFLAGS="-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 "
|
/bin/bash -c "
|
||||||
cd /buildfs && \
|
cd /buildfs && \
|
||||||
cmake /abseil-cpp \
|
cmake /abseil-cpp \
|
||||||
|
|
Loading…
Reference in a new issue