diff options
-rw-r--r-- | absl/base/log_severity.h | 52 | ||||
-rw-r--r-- | absl/flags/flag.h | 12 | ||||
-rw-r--r-- | absl/flags/flag_test.cc | 23 | ||||
-rw-r--r-- | absl/flags/internal/flag.h | 14 | ||||
-rw-r--r-- | absl/functional/bind_front.h | 58 |
5 files changed, 126 insertions, 33 deletions
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h index e247c4a9..65a3b166 100644 --- a/absl/base/log_severity.h +++ b/absl/base/log_severity.h @@ -24,19 +24,45 @@ namespace absl { ABSL_NAMESPACE_BEGIN -// Four severity levels are defined. Logging APIs should terminate the program +// absl::LogSeverity +// +// Four severity levels are defined. Logging APIs should terminate the program // when a message is logged at severity `kFatal`; the other levels have no // special semantics. // -// Abseil flags may be defined with type `LogSeverity`. Dependency layering -// constraints require that the `AbslParseFlag` overload be declared and defined -// in the flags module rather than here. The `AbslUnparseFlag` overload is -// defined there too for consistency. +// Values other than the four defined levels (e.g. produced by `static_cast`) +// are valid, but their semantics when passed to a function, macro, or flag +// depend on the function, macro, or flag. The usual behavior is to normalize +// such values to a defined severity level, however in some cases values other +// than the defined levels are useful for comparison. +// +// Exmaple: +// +// // Effectively disables all logging: +// SetMinLogLevel(static_cast<absl::LogSeverity>(100)); +// +// Abseil flags may be defined with type `LogSeverity`. Dependency layering +// constraints require that the `AbslParseFlag()` overload be declared and +// defined in the flags library itself rather than here. The `AbslUnparseFlag()` +// overload is defined there as well for consistency. +// +// absl::LogSeverity Flag String Representation +// +// An `absl::LogSeverity` has a string representation used for parsing +// command-line flags based on the enumerator name (e.g. `kFatal`) or +// its unprefixed name (without the `k`) in any case-insensitive form. (E.g. +// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an +// unprefixed string representation in all caps (e.g. "FATAL") or an integer. // -// The parser accepts arbitrary integers (as if the type were `int`). It also -// accepts each named enumerator, without regard for case, with or without the -// leading 'k'. For example: "kInfo", "INFO", and "info" all parse to the value -// `absl::LogSeverity::kInfo`. +// Additionally, the parser accepts arbitrary integers (as if the type were +// `int`). +// +// Examples: +// +// --my_log_level=kInfo +// --my_log_level=INFO +// --my_log_level=info +// --my_log_level=0 // // Unparsing a flag produces the same result as `absl::LogSeverityName()` for // the standard levels and a base-ten integer otherwise. @@ -47,6 +73,8 @@ enum class LogSeverity : int { kFatal = 3, }; +// LogSeverities() +// // Returns an iterable of all standard `absl::LogSeverity` values, ordered from // least to most severe. constexpr std::array<absl::LogSeverity, 4> LogSeverities() { @@ -54,6 +82,8 @@ constexpr std::array<absl::LogSeverity, 4> LogSeverities() { absl::LogSeverity::kError, absl::LogSeverity::kFatal}}; } +// LogSeverityName() +// // Returns the all-caps string representation (e.g. "INFO") of the specified // severity level if it is one of the standard levels and "UNKNOWN" otherwise. constexpr const char* LogSeverityName(absl::LogSeverity s) { @@ -66,6 +96,8 @@ constexpr const char* LogSeverityName(absl::LogSeverity s) { : s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN"; } +// NormalizeLogSeverity() +// // Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal` // normalize to `kError` (**NOT** `kFatal`). constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) { @@ -77,6 +109,8 @@ constexpr absl::LogSeverity NormalizeLogSeverity(int s) { return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s)); } +// operator<< +// // The exact representation of a streamed `absl::LogSeverity` is deliberately // unspecified; do not rely on it. std::ostream& operator<<(std::ostream& os, absl::LogSeverity s); diff --git a/absl/flags/flag.h b/absl/flags/flag.h index b6fbd116..f18e9f56 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -384,11 +384,19 @@ ABSL_NAMESPACE_END // // `default_value` is only used as a double check on the type. `explanation` is // unused. +// +// ABSL_RETIRED_FLAG support omitting the default value for default +// constructible value type, so that users can delete the code generatring this +// value. +// // TODO(rogeeff): Return an anonymous struct instead of bool, and place it into // the unnamed namespace. #define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \ - ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname = \ - ([] { return type(default_value); }, \ + ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname = \ + ([] { \ + return absl::flags_internal::MakeFromDefaultValueOrEmpty<type>( \ + default_value); \ + }, \ absl::flags_internal::RetiredFlag<type>(#flagname)) #endif // ABSL_FLAGS_FLAG_H_ diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 4e08da85..465f018c 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -486,11 +486,30 @@ TEST_F(FlagTest, TestNonDefaultConstructibleType) { // -------------------------------------------------------------------- +struct Wrapper { + Wrapper() {} + + // NOLINTNEXTLINE(runtime/explicit) + Wrapper(const std::string& val) : val(val) {} + + // NOLINTNEXTLINE(runtime/explicit) + template <typename T> + Wrapper(T&& t) : val(std::forward<T>(t)) {} + + // NOLINTNEXTLINE(runtime/explicit) + operator std::string() const& { return val; } + + std::string val; +}; + } // namespace ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr"); ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr"); ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr")); +ABSL_RETIRED_FLAG(Wrapper, old_wrapper_flag, {}, "old wrapper"); +ABSL_RETIRED_FLAG(Wrapper, old_wrapper_no_default_flag, , + "old wrapper no default"); namespace { @@ -502,6 +521,10 @@ TEST_F(FlagTest, TestRetiredFlagRegistration) { EXPECT_FALSE(is_bool); EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool)); EXPECT_FALSE(is_bool); + EXPECT_TRUE(flags::IsRetiredFlag("old_wrapper_flag", &is_bool)); + EXPECT_FALSE(is_bool); + EXPECT_TRUE(flags::IsRetiredFlag("old_wrapper_no_default_flag", &is_bool)); + EXPECT_FALSE(is_bool); EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool)); } diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index 20de406f..21a10c7f 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -416,6 +416,20 @@ T* MakeFromDefaultValue(EmptyBraces) { return new T; } +// MakeFromDefaultValueOrEmpty is basically the same as MakeFromDefaultValue. It +// also allows for empty macro parameter (hence no argument), which was somehow +// widely used for ABSL_RETIRED_FLAG(). + +template <typename T> +T* MakeFromDefaultValueOrEmpty(T t) { + return MakeFromDefaultValue(std::move(t)); +} + +template <typename T> +T* MakeFromDefaultValueOrEmpty() { + return MakeFromDefaultValue<T>(EmptyBraces()); +} + } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/functional/bind_front.h b/absl/functional/bind_front.h index 4c61d0ec..8448d7b3 100644 --- a/absl/functional/bind_front.h +++ b/absl/functional/bind_front.h @@ -11,17 +11,44 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - +// +// ----------------------------------------------------------------------------- +// File: bind_front.h +// ----------------------------------------------------------------------------- +// // `absl::bind_front()` returns a functor by binding a number of arguments to -// the front of a provided functor, allowing you to avoid known problems with -// `std::bind()`. It is a form of partial function application -// https://en.wikipedia.org/wiki/Partial_application. +// the front of a provided (usually more generic) functor. Unlike `std::bind`, +// it does not require the use of argument placeholders. The simpler syntax of +// `absl::bind_front()` allows you to avoid known misuses with `std::bind()`. +// +// `absl::bind_front()` is meant as a drop-in replacement for C++20's upcoming +// `std::bind_front()`, which similarly resolves these issues with +// `std::bind()`. Both `bind_front()` alternatives, unlike `std::bind()`, allow +// partial function application. (See +// https://en.wikipedia.org/wiki/Partial_application). + +#ifndef ABSL_FUNCTIONAL_BIND_FRONT_H_ +#define ABSL_FUNCTIONAL_BIND_FRONT_H_ + +#include "absl/functional/internal/front_binder.h" +#include "absl/utility/utility.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +// bind_front() +// +// Binds the first N arguments of an invocable object and stores them by value, +// except types of `std::reference_wrapper` which are 'unwound' and stored by +// reference. // -// Like `std::bind()` it is implicitly convertible to `std::function`. In -// particular, it may be used as a simpler replacement for `std::bind()` in most -// cases, as it does not require placeholders to be specified. More -// importantly, it provides more reliable correctness guarantees than -// `std::bind()`. +// Like `std::bind()`, `absl::bind_front()` is implicitly convertible to +// `std::function`. In particular, it may be used as a simpler replacement for +// `std::bind()` in most cases, as it does not require placeholders to be +// specified. More importantly, it provides more reliable correctness guarantees +// than `std::bind()`; while `std::bind()` will silently ignore passing more +// parameters than expected, for example, `absl::bind_front()` will report such +// mis-uses as errors. // // absl::bind_front(a...) can be seen as storing the results of // std::make_tuple(a...). @@ -125,19 +152,6 @@ // // dangling references. // foo->DoInFuture(absl::bind_front(Print, std::ref(hi), "Guest")); // BAD! // auto f = absl::bind_front(Print, std::ref(hi), "Guest"); // BAD! - -#ifndef ABSL_FUNCTIONAL_BIND_FRONT_H_ -#define ABSL_FUNCTIONAL_BIND_FRONT_H_ - -#include "absl/functional/internal/front_binder.h" -#include "absl/utility/utility.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -// Binds the first N arguments of an invocable object and stores them by value, -// except types of std::reference_wrapper which are 'unwound' and stored by -// reference. template <class F, class... BoundArgs> constexpr functional_internal::bind_front_t<F, BoundArgs...> bind_front( F&& func, BoundArgs&&... args) { |