summaryrefslogtreecommitdiff
path: root/absl/flags/internal/usage.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2020-11-19 11:40:19 -0800
committerGravatar Derek Mauro <dmauro@google.com>2020-11-19 14:57:28 -0500
commit4fd9a1ec5077daac14eeee05df931d658ec0b7b8 (patch)
tree710d691ac5231c60347f7da680b2c8189b45a174 /absl/flags/internal/usage.cc
parent4ae6730677ea3c2984f8bb0e4919bd0d9dd04f73 (diff)
Export of internal Abseil changes
-- 03700706d80f0939e2b5b8c02a326f045b643730 by Abseil Team <absl-team@google.com>: Reduced latency and code-size of some InlinedVector methods: 1. Simpler fast path for push_back/emplace_back. 2. Do not inline slow path of push-back/emplace_back. 3. Simplify resize implementation. Performance: A simple benchmark that does the following per iteration: ``` push_back on an InlinedVector<int64> push_back on an InlinedVector<bool> ``` Sees iteration time go from 4.3ns to 2.8ns and code size shrink from 1129 bytes to 175 bytes. PiperOrigin-RevId: 343335635 -- 16f74277a9e8bf228c164b053da8b8098f76de62 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 343332753 -- 886b6d5d0244783d309e34f03c21710f411e3cb3 by Abseil Team <absl-team@google.com>: Optimize `Status::Status`: When creating a status, we currently create an empty struct first, then assign fields. This is suboptimal: https://screenshot.googleplex.com/5HqDuFBKUEqrVgy. Relevant Benchmarks: ``` BM_StatusCopyError_Deep/threads:1 26.9ns ±13% 21.2ns ±16% -21.46% (p=0.000 n=15+15) BM_StatusCopyError_Deep/threads:2 32.0ns ±30% 25.6ns ±37% -20.17% (p=0.004 n=15+14) BM_StatusCopyError_Deep/threads:4 37.4ns ±84% 30.6ns ±58% -18.26% (p=0.029 n=15+15) BM_StatusCopyError_Deep/threads:8 47.2ns ±33% 33.5ns ±56% -28.91% (p=0.000 n=15+14) ``` PiperOrigin-RevId: 343303312 -- 2f9d945654292e8e52cad410fa41dae794cff42c by Abseil Team <absl-team@google.com>: Set SOVERSION for the installed libraries PiperOrigin-RevId: 343287682 -- 600bbfffe91cfbdc60b43cdad5619258298d0b0d by Abseil Team <absl-team@google.com>: Fix a typo in a comment (than -> that) PiperOrigin-RevId: 343187724 -- 310c82cd97b3f1f0d1ee93a0ee2b0aee828b2a93 by Abseil Team <absl-team@google.com>: Simplify unaligned memory access functions. The #ifdef to produce calls to __sanitizer_unaligned_load16 etc were needed in past versions of this code, when we were lying to the compiler about the alignment of the loads/stores, by using a reinterpret_cast. However, a year ago, absl switched to simply use memcpy. Sanitizers support this correctly by default, nothing extra is required. PiperOrigin-RevId: 343159883 -- bdf6fcf99180c371fda6ba8af82fd44656e372fa by Gennadiy Rozental <rogeeff@google.com>: Migrate usage flags to global variables instead of modeling them as Abseil Flags. Also introduce new semantic for --help=substring command line argument. PiperOrigin-RevId: 343019883 GitOrigin-RevId: 03700706d80f0939e2b5b8c02a326f045b643730 Change-Id: I4ad40dfa9606f8b8bfb2d91fd09e327105311bfb
Diffstat (limited to 'absl/flags/internal/usage.cc')
-rw-r--r--absl/flags/internal/usage.cc274
1 files changed, 203 insertions, 71 deletions
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index 75573227..f29d7c9b 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -37,26 +37,26 @@
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
-ABSL_FLAG(bool, help, false,
- "show help on important flags for this binary [tip: all flags can "
- "have two dashes]");
-ABSL_FLAG(bool, helpfull, false, "show help on all flags");
-ABSL_FLAG(bool, helpshort, false,
- "show help on only the main module for this program");
-ABSL_FLAG(bool, helppackage, false,
- "show help on all modules in the main package");
-ABSL_FLAG(bool, version, false, "show version and build info and exit");
-ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags");
-ABSL_FLAG(std::string, helpon, "",
- "show help on the modules named by this flag value");
-ABSL_FLAG(std::string, helpmatch, "",
- "show help on modules whose name contains the specified substr");
+// Dummy global variables to prevent anyone else defining these.
+bool FLAGS_help = false;
+bool FLAGS_helpfull = false;
+bool FLAGS_helpshort = false;
+bool FLAGS_helppackage = false;
+bool FLAGS_version = false;
+bool FLAGS_only_check_args = false;
+bool FLAGS_helpon = false;
+bool FLAGS_helpmatch = false;
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace flags_internal {
namespace {
+using PerFlagFilter = std::function<bool(const absl::CommandLineFlag&)>;
+
+// Maximum length size in a human readable format.
+constexpr size_t kHrfMaxLineLength = 80;
+
// This class is used to emit an XML element with `tag` and `text`.
// It adds opening and closing tags and escapes special characters in the text.
// For example:
@@ -109,9 +109,12 @@ class FlagHelpPrettyPrinter {
public:
// Pretty printer holds on to the std::ostream& reference to direct an output
// to that stream.
- FlagHelpPrettyPrinter(int max_line_len, std::ostream& out)
+ FlagHelpPrettyPrinter(size_t max_line_len, size_t min_line_len,
+ size_t wrapped_line_indent, std::ostream& out)
: out_(out),
max_line_len_(max_line_len),
+ min_line_len_(min_line_len),
+ wrapped_line_indent_(wrapped_line_indent),
line_len_(0),
first_line_(true) {}
@@ -165,13 +168,12 @@ class FlagHelpPrettyPrinter {
void StartLine() {
if (first_line_) {
- out_ << " ";
- line_len_ = 4;
+ line_len_ = min_line_len_;
first_line_ = false;
} else {
- out_ << " ";
- line_len_ = 6;
+ line_len_ = min_line_len_ + wrapped_line_indent_;
}
+ out_ << std::string(line_len_, ' ');
}
void EndLine() {
out_ << '\n';
@@ -180,13 +182,15 @@ class FlagHelpPrettyPrinter {
private:
std::ostream& out_;
- const int max_line_len_;
- int line_len_;
+ const size_t max_line_len_;
+ const size_t min_line_len_;
+ const size_t wrapped_line_indent_;
+ size_t line_len_;
bool first_line_;
};
void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
- FlagHelpPrettyPrinter printer(80, out); // Max line length is 80.
+ FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 4, 2, out);
// Flag name.
printer.Write(absl::StrCat("--", flag.Name()));
@@ -222,7 +226,7 @@ void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
// If a flag's help message has been stripped (e.g. by adding '#define
// STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help'
// and its variants.
-void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
+void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb,
HelpFormat format, absl::string_view program_usage_message) {
if (format == HelpFormat::kHumanReadable) {
out << flags_internal::ShortProgramInvocationName() << ": "
@@ -257,10 +261,10 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
// If the flag has been stripped, pretend that it doesn't exist.
if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
- std::string flag_filename = flag.Filename();
-
// Make sure flag satisfies the filter
- if (!filter_cb || !filter_cb(flag_filename)) return;
+ if (!filter_cb(flag)) return;
+
+ std::string flag_filename = flag.Filename();
matching_flags[std::string(flags_internal::Package(flag_filename))]
[flag_filename]
@@ -290,15 +294,34 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
}
if (format == HelpFormat::kHumanReadable) {
+ FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 0, 0, out);
+
if (filter_cb && matching_flags.empty()) {
- out << " No modules matched: use -helpfull\n";
+ printer.Write("No flags matched.\n", true);
}
+ printer.EndLine();
+ printer.Write(
+ "Try --helpfull to get a list of all flags or --help=substring "
+ "shows help for flags which include specified substring in either "
+ "in the name, or description or path.\n",
+ true);
} else {
// The end of the document.
out << "</AllFlags>\n";
}
}
+void FlagsHelpImpl(std::ostream& out,
+ flags_internal::FlagKindFilter filename_filter_cb,
+ HelpFormat format, absl::string_view program_usage_message) {
+ FlagsHelpImpl(
+ out,
+ [&](const absl::CommandLineFlag& flag) {
+ return filename_filter_cb && filename_filter_cb(flag.Filename());
+ },
+ format, program_usage_message);
+}
+
} // namespace
// --------------------------------------------------------------------
@@ -310,7 +333,7 @@ void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
}
// --------------------------------------------------------------------
-// Produces the help messages for all flags matching the filter.
+// Produces the help messages for all flags matching the filename filter.
// If filter is empty produces help messages for all flags.
void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
absl::string_view program_usage_message) {
@@ -325,66 +348,175 @@ void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
// If so, handles them appropriately.
int HandleUsageFlags(std::ostream& out,
absl::string_view program_usage_message) {
- if (absl::GetFlag(FLAGS_helpshort)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_helpshort_flags,
- HelpFormat::kHumanReadable, program_usage_message);
- return 1;
- }
+ switch (GetFlagsHelpMode()) {
+ case HelpMode::kNone:
+ break;
+ case HelpMode::kImportant:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_help_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+ return 1;
+
+ case HelpMode::kShort:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helpshort_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+ return 1;
+
+ case HelpMode::kFull:
+ flags_internal::FlagsHelp(out, "", GetFlagsHelpFormat(),
+ program_usage_message);
+ return 1;
+
+ case HelpMode::kPackage:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helppackage_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+
+ return 1;
+
+ case HelpMode::kMatch: {
+ std::string substr = GetFlagsHelpMatchSubstr();
+ if (substr.empty()) {
+ // show all options
+ flags_internal::FlagsHelp(out, substr, GetFlagsHelpFormat(),
+ program_usage_message);
+ } else {
+ auto filter_cb = [&substr](const absl::CommandLineFlag& flag) {
+ if (absl::StrContains(flag.Name(), substr)) return true;
+ if (absl::StrContains(flag.Filename(), substr)) return true;
+ if (absl::StrContains(flag.Help(), substr)) return true;
+
+ return false;
+ };
+ flags_internal::FlagsHelpImpl(
+ out, filter_cb, HelpFormat::kHumanReadable, program_usage_message);
+ }
- if (absl::GetFlag(FLAGS_helpfull)) {
- // show all options
- flags_internal::FlagsHelp(out, "", HelpFormat::kHumanReadable,
- program_usage_message);
- return 1;
+ return 1;
+ }
+ case HelpMode::kVersion:
+ if (flags_internal::GetUsageConfig().version_string)
+ out << flags_internal::GetUsageConfig().version_string();
+ // Unlike help, we may be asking for version in a script, so return 0
+ return 0;
+
+ case HelpMode::kOnlyCheckArgs:
+ return 0;
}
- if (!absl::GetFlag(FLAGS_helpon).empty()) {
- flags_internal::FlagsHelp(
- out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."),
- HelpFormat::kHumanReadable, program_usage_message);
- return 1;
- }
+ return -1;
+}
- if (!absl::GetFlag(FLAGS_helpmatch).empty()) {
- flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch),
- HelpFormat::kHumanReadable,
- program_usage_message);
- return 1;
- }
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
+
+namespace {
+
+ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit);
+ABSL_CONST_INIT std::string* match_substr
+ ABSL_GUARDED_BY(help_attributes_guard) = nullptr;
+ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) =
+ HelpMode::kNone;
+ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) =
+ HelpFormat::kHumanReadable;
+
+} // namespace
- if (absl::GetFlag(FLAGS_help)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_help_flags,
- HelpFormat::kHumanReadable, program_usage_message);
+std::string GetFlagsHelpMatchSubstr() {
+ absl::MutexLock l(&help_attributes_guard);
+ if (match_substr == nullptr) return "";
+ return *match_substr;
+}
- out << "\nTry --helpfull to get a list of all flags.\n";
+void SetFlagsHelpMatchSubstr(absl::string_view substr) {
+ absl::MutexLock l(&help_attributes_guard);
+ if (match_substr == nullptr) match_substr = new std::string;
+ match_substr->assign(substr.data(), substr.size());
+}
- return 1;
+HelpMode GetFlagsHelpMode() {
+ absl::MutexLock l(&help_attributes_guard);
+ // Refer to dummy variales to prevent linker dropping them
+ if (FLAGS_help || FLAGS_helpfull || FLAGS_helpshort || FLAGS_helppackage ||
+ FLAGS_version || FLAGS_only_check_args || FLAGS_helpon ||
+ FLAGS_helpmatch) {
+ help_mode = HelpMode::kNone;
}
+ return help_mode;
+}
+
+void SetFlagsHelpMode(HelpMode mode) {
+ absl::MutexLock l(&help_attributes_guard);
+ help_mode = mode;
+}
- if (absl::GetFlag(FLAGS_helppackage)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_helppackage_flags,
- HelpFormat::kHumanReadable, program_usage_message);
+HelpFormat GetFlagsHelpFormat() {
+ absl::MutexLock l(&help_attributes_guard);
+ return help_format;
+}
+
+void SetFlagsHelpFormat(HelpFormat format) {
+ absl::MutexLock l(&help_attributes_guard);
+ help_format = format;
+}
- out << "\nTry --helpfull to get a list of all flags.\n";
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value) {
+ if (absl::ConsumePrefix(&name, "help")) {
+ if (name == "") {
+ if (value.empty()) {
+ SetFlagsHelpMode(HelpMode::kImportant);
+ } else {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(value);
+ }
+ return true;
+ }
- return 1;
+ if (name == "match") {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(value);
+ return true;
+ }
+
+ if (name == "on") {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(absl::StrCat("/", value, "."));
+ return true;
+ }
+
+ if (name == "full") {
+ SetFlagsHelpMode(HelpMode::kFull);
+ return true;
+ }
+
+ if (name == "short") {
+ SetFlagsHelpMode(HelpMode::kShort);
+ return true;
+ }
+
+ if (name == "package") {
+ SetFlagsHelpMode(HelpMode::kPackage);
+ return true;
+ }
+
+ return false;
}
- if (absl::GetFlag(FLAGS_version)) {
- if (flags_internal::GetUsageConfig().version_string)
- out << flags_internal::GetUsageConfig().version_string();
- // Unlike help, we may be asking for version in a script, so return 0
- return 0;
+ if (name == "version") {
+ SetFlagsHelpMode(HelpMode::kVersion);
+ return true;
}
- if (absl::GetFlag(FLAGS_only_check_args)) {
- return 0;
+ if (name == "only_check_args") {
+ SetFlagsHelpMode(HelpMode::kOnlyCheckArgs);
+ return true;
}
- return -1;
+ return false;
}
} // namespace flags_internal