diff options
Diffstat (limited to 'absl/flags')
-rw-r--r-- | absl/flags/internal/flag.h | 64 | ||||
-rw-r--r-- | absl/flags/internal/parse.h | 7 | ||||
-rw-r--r-- | absl/flags/parse.cc | 40 | ||||
-rw-r--r-- | absl/flags/parse_test.cc | 22 |
4 files changed, 119 insertions, 14 deletions
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index f53f484f..b060199e 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -40,6 +40,30 @@ namespace absl { ABSL_NAMESPACE_BEGIN + +// Forward declaration of absl::Flag<T> public API. +namespace flags_internal { +template <typename T> +class Flag; +} // namespace flags_internal + +#if defined(_MSC_VER) && !defined(__clang__) +template <typename T> +class Flag; +#else +template <typename T> +using Flag = flags_internal::Flag<T>; +#endif + +template <typename T> +ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag); + +template <typename T> +void SetFlag(absl::Flag<T>* flag, const T& v); + +template <typename T, typename V> +void SetFlag(absl::Flag<T>* flag, const V& v); + namespace flags_internal { /////////////////////////////////////////////////////////////////////////////// @@ -596,6 +620,32 @@ class Flag { flags_internal::StorageKind<T>(), default_arg), value_() {} + // CommandLineFlag interface + absl::string_view Name() const { return impl_.Name(); } + std::string Filename() const { return impl_.Filename(); } + std::string Help() const { return impl_.Help(); } + bool IsSpecifiedOnCommandLine() const { + return impl_.IsSpecifiedOnCommandLine(); + } + std::string DefaultValue() const { return impl_.DefaultValue(); } + std::string CurrentValue() const { return impl_.CurrentValue(); } + + private: + template <typename U, bool do_register> + friend class FlagRegistrar; + +#if !defined(_MSC_VER) || defined(__clang__) + template <typename U> + friend U absl::GetFlag(const flags_internal::Flag<U>& flag); + template <typename U> + friend void absl::SetFlag(flags_internal::Flag<U>* flag, const U& v); + template <typename U, typename V> + friend void absl::SetFlag(flags_internal::Flag<U>* flag, const V& v); +#else + template <typename U> + friend class absl::Flag; +#endif + T Get() const { // See implementation notes in CommandLineFlag::Get(). union U { @@ -617,20 +667,6 @@ class Flag { impl_.Write(&v); } - // CommandLineFlag interface - absl::string_view Name() const { return impl_.Name(); } - std::string Filename() const { return impl_.Filename(); } - std::string Help() const { return impl_.Help(); } - bool IsSpecifiedOnCommandLine() const { - return impl_.IsSpecifiedOnCommandLine(); - } - std::string DefaultValue() const { return impl_.DefaultValue(); } - std::string CurrentValue() const { return impl_.CurrentValue(); } - - private: - template <typename U, bool do_register> - friend class FlagRegistrar; - // Flag's data // The implementation depends on value_ field to be placed exactly after the // impl_ field, so that impl_ can figure out the offset to the value and diff --git a/absl/flags/internal/parse.h b/absl/flags/internal/parse.h index 03e8a07b..d259be73 100644 --- a/absl/flags/internal/parse.h +++ b/absl/flags/internal/parse.h @@ -44,6 +44,13 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], UsageFlagsAction usage_flag_act, OnUndefinedFlag on_undef_flag); +// -------------------------------------------------------------------- +// Inspect original command line + +// Returns true if flag with specified name was either present on the original +// command line or specified in flag file present on the original command line. +bool WasPresentOnCommandLine(absl::string_view flag_name); + } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index 66a28a93..2e8f03b4 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc @@ -67,6 +67,22 @@ ABSL_CONST_INIT bool fromenv_needs_processing ABSL_CONST_INIT bool tryfromenv_needs_processing ABSL_GUARDED_BY(processing_checks_guard) = false; +ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit); +ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags + ABSL_GUARDED_BY(specified_flags_guard) = nullptr; + +struct SpecifiedFlagsCompare { + bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const { + return a->Name() < b->Name(); + } + bool operator()(const CommandLineFlag* a, absl::string_view b) const { + return a->Name() < b; + } + bool operator()(absl::string_view a, const CommandLineFlag* b) const { + return a < b->Name(); + } +}; + } // namespace } // namespace flags_internal ABSL_NAMESPACE_END @@ -577,6 +593,17 @@ bool CanIgnoreUndefinedFlag(absl::string_view flag_name) { // -------------------------------------------------------------------- +bool WasPresentOnCommandLine(absl::string_view flag_name) { + absl::MutexLock l(&specified_flags_guard); + ABSL_INTERNAL_CHECK(specified_flags != nullptr, + "ParseCommandLine is not invoked yet"); + + return std::binary_search(specified_flags->begin(), specified_flags->end(), + flag_name, SpecifiedFlagsCompare{}); +} + +// -------------------------------------------------------------------- + std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], ArgvListAction arg_list_act, UsageFlagsAction usage_flag_act, @@ -607,6 +634,13 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], } output_args.push_back(argv[0]); + absl::MutexLock l(&specified_flags_guard); + if (specified_flags == nullptr) { + specified_flags = new std::vector<const CommandLineFlag*>; + } else { + specified_flags->clear(); + } + // Iterate through the list of the input arguments. First level are arguments // originated from argc/argv. Following levels are arguments originated from // recursive parsing of flagfile(s). @@ -702,6 +736,8 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], flag, value, SET_FLAGS_VALUE, kCommandLine, &error)) { flags_internal::ReportUsageError(error, true); success = false; + } else { + specified_flags->push_back(flag); } } @@ -753,6 +789,10 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], } } + // Trim and sort the vector. + specified_flags->shrink_to_fit(); + std::sort(specified_flags->begin(), specified_flags->end(), + SpecifiedFlagsCompare{}); return output_args; } diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc index 065f757a..e6a53ae6 100644 --- a/absl/flags/parse_test.cc +++ b/absl/flags/parse_test.cc @@ -869,4 +869,26 @@ TEST_F(ParseDeathTest, TestHelpFlagHandling) { EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3); } +// -------------------------------------------------------------------- + +TEST_F(ParseTest, WasPresentOnCommandLine) { + const char* in_args1[] = { + "testbin", "arg1", "--bool_flag", + "--int_flag=211", "arg2", "--double_flag=1.1", + "--string_flag", "asd", "--", + "--some_flag", "arg4", + }; + + InvokeParse(in_args1); + + EXPECT_TRUE(flags::WasPresentOnCommandLine("bool_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("int_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("double_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("string_flag")); + EXPECT_FALSE(flags::WasPresentOnCommandLine("some_flag")); + EXPECT_FALSE(flags::WasPresentOnCommandLine("another_flag")); +} + +// -------------------------------------------------------------------- + } // namespace |