Commit 4fd9a1ec by Abseil Team Committed by Derek Mauro

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
parent 4ae67306
...@@ -260,6 +260,8 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n") ...@@ -260,6 +260,8 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
if(ABSL_ENABLE_INSTALL) if(ABSL_ENABLE_INSTALL)
set_target_properties(${_NAME} PROPERTIES set_target_properties(${_NAME} PROPERTIES
OUTPUT_NAME "absl_${_NAME}" OUTPUT_NAME "absl_${_NAME}"
# TODO(b/173696973): Figure out how to set SOVERSION for LTS releases.
SOVERSION 0
) )
endif() endif()
else() else()
......
...@@ -31,70 +31,6 @@ ...@@ -31,70 +31,6 @@
// The unaligned API is C++ only. The declarations use C++ features // The unaligned API is C++ only. The declarations use C++ features
// (namespaces, inline) which are absent or incompatible in C. // (namespaces, inline) which are absent or incompatible in C.
#if defined(__cplusplus) #if defined(__cplusplus)
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
defined(ABSL_HAVE_THREAD_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
// will miss a bug if 08 is the first unaddressable byte.
// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
// miss a race between this access and some other accesses to 08.
// MemorySanitizer will correctly propagate the shadow on unaligned stores
// and correctly report bugs on unaligned loads, but it may not properly
// update and report the origin of the uninitialized memory.
// For all three tools, replacing an unaligned access with a tool-specific
// callback solves the problem.
#include <sanitizer/common_interface_defs.h>
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) {
return __sanitizer_unaligned_load16(p);
}
inline uint32_t UnalignedLoad32(const void *p) {
return __sanitizer_unaligned_load32(p);
}
inline uint64_t UnalignedLoad64(const void *p) {
return __sanitizer_unaligned_load64(p);
}
inline void UnalignedStore16(void *p, uint16_t v) {
__sanitizer_unaligned_store16(p, v);
}
inline void UnalignedStore32(void *p, uint32_t v) {
__sanitizer_unaligned_store32(p, v);
}
inline void UnalignedStore64(void *p, uint64_t v) {
__sanitizer_unaligned_store64(p, v);
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
(absl::base_internal::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(absl::base_internal::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::base_internal::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::base_internal::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val))
#else
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
...@@ -141,8 +77,6 @@ ABSL_NAMESPACE_END ...@@ -141,8 +77,6 @@ ABSL_NAMESPACE_END
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val)) (absl::base_internal::UnalignedStore64(_p, _val))
#endif
#endif // defined(__cplusplus), end of unaligned API #endif // defined(__cplusplus), end of unaligned API
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ #endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
...@@ -179,7 +179,7 @@ ...@@ -179,7 +179,7 @@
#endif #endif
// ABSL_INTERNAL_ASSUME(cond) // ABSL_INTERNAL_ASSUME(cond)
// Informs the compiler than a condition is always true and that it can assume // Informs the compiler that a condition is always true and that it can assume
// it to be true for optimization purposes. The call has undefined behavior if // it to be true for optimization purposes. The call has undefined behavior if
// the condition is false. // the condition is false.
// In !NDEBUG mode, the condition is checked with an assert(). // In !NDEBUG mode, the condition is checked with an assert().
......
...@@ -462,6 +462,9 @@ class Storage { ...@@ -462,6 +462,9 @@ class Storage {
Inlined inlined; Inlined inlined;
}; };
template <typename... Args>
ABSL_ATTRIBUTE_NOINLINE reference EmplaceBackSlow(Args&&... args);
Metadata metadata_; Metadata metadata_;
Data data_; Data data_;
}; };
...@@ -542,48 +545,42 @@ template <typename T, size_t N, typename A> ...@@ -542,48 +545,42 @@ template <typename T, size_t N, typename A>
template <typename ValueAdapter> template <typename ValueAdapter>
auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void { auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
StorageView storage_view = MakeStorageView(); StorageView storage_view = MakeStorageView();
auto* const base = storage_view.data;
IteratorValueAdapter<MoveIterator> move_values( const size_type size = storage_view.size;
MoveIterator(storage_view.data)); auto* alloc = GetAllocPtr();
if (new_size <= size) {
AllocationTransaction allocation_tx(GetAllocPtr()); // Destroy extra old elements.
ConstructionTransaction construction_tx(GetAllocPtr()); inlined_vector_internal::DestroyElements(alloc, base + new_size,
size - new_size);
absl::Span<value_type> construct_loop; } else if (new_size <= storage_view.capacity) {
absl::Span<value_type> move_construct_loop; // Construct new elements in place.
absl::Span<value_type> destroy_loop; inlined_vector_internal::ConstructElements(alloc, base + size, &values,
new_size - size);
if (new_size > storage_view.capacity) { } else {
// Steps:
// a. Allocate new backing store.
// b. Construct new elements in new backing store.
// c. Move existing elements from old backing store to now.
// d. Destroy all elements in old backing store.
// Use transactional wrappers for the first two steps so we can roll
// back if necessary due to exceptions.
AllocationTransaction allocation_tx(alloc);
size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size); size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
pointer new_data = allocation_tx.Allocate(new_capacity); pointer new_data = allocation_tx.Allocate(new_capacity);
construct_loop = {new_data + storage_view.size,
new_size - storage_view.size};
move_construct_loop = {new_data, storage_view.size};
destroy_loop = {storage_view.data, storage_view.size};
} else if (new_size > storage_view.size) {
construct_loop = {storage_view.data + storage_view.size,
new_size - storage_view.size};
} else {
destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
}
construction_tx.Construct(construct_loop.data(), &values,
construct_loop.size());
inlined_vector_internal::ConstructElements( ConstructionTransaction construction_tx(alloc);
GetAllocPtr(), move_construct_loop.data(), &move_values, construction_tx.Construct(new_data + size, &values, new_size - size);
move_construct_loop.size());
inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(), IteratorValueAdapter<MoveIterator> move_values((MoveIterator(base)));
destroy_loop.size()); inlined_vector_internal::ConstructElements(alloc, new_data, &move_values,
size);
construction_tx.Commit(); inlined_vector_internal::DestroyElements(alloc, base, size);
if (allocation_tx.DidAllocate()) { construction_tx.Commit();
DeallocateIfAllocated(); DeallocateIfAllocated();
AcquireAllocatedData(&allocation_tx); AcquireAllocatedData(&allocation_tx);
SetIsAllocated(); SetIsAllocated();
} }
SetSize(new_size); SetSize(new_size);
} }
...@@ -684,44 +681,50 @@ template <typename T, size_t N, typename A> ...@@ -684,44 +681,50 @@ template <typename T, size_t N, typename A>
template <typename... Args> template <typename... Args>
auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference { auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference {
StorageView storage_view = MakeStorageView(); StorageView storage_view = MakeStorageView();
const auto n = storage_view.size;
if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) {
// Fast path; new element fits.
pointer last_ptr = storage_view.data + n;
AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
std::forward<Args>(args)...);
AddSize(1);
return *last_ptr;
}
// TODO(b/173712035): Annotate with musttail attribute to prevent regression.
return EmplaceBackSlow(std::forward<Args>(args)...);
}
template <typename T, size_t N, typename A>
template <typename... Args>
auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> reference {
StorageView storage_view = MakeStorageView();
AllocationTransaction allocation_tx(GetAllocPtr()); AllocationTransaction allocation_tx(GetAllocPtr());
IteratorValueAdapter<MoveIterator> move_values( IteratorValueAdapter<MoveIterator> move_values(
MoveIterator(storage_view.data)); MoveIterator(storage_view.data));
size_type new_capacity = NextCapacity(storage_view.capacity);
pointer construct_data; pointer construct_data = allocation_tx.Allocate(new_capacity);
if (storage_view.size == storage_view.capacity) {
size_type new_capacity = NextCapacity(storage_view.capacity);
construct_data = allocation_tx.Allocate(new_capacity);
} else {
construct_data = storage_view.data;
}
pointer last_ptr = construct_data + storage_view.size; pointer last_ptr = construct_data + storage_view.size;
// Construct new element.
AllocatorTraits::construct(*GetAllocPtr(), last_ptr, AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
std::forward<Args>(args)...); std::forward<Args>(args)...);
// Move elements from old backing store to new backing store.
if (allocation_tx.DidAllocate()) { ABSL_INTERNAL_TRY {
ABSL_INTERNAL_TRY { inlined_vector_internal::ConstructElements(
inlined_vector_internal::ConstructElements( GetAllocPtr(), allocation_tx.GetData(), &move_values,
GetAllocPtr(), allocation_tx.GetData(), &move_values, storage_view.size);
storage_view.size);
}
ABSL_INTERNAL_CATCH_ANY {
AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
ABSL_INTERNAL_RETHROW;
}
inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
storage_view.size);
DeallocateIfAllocated();
AcquireAllocatedData(&allocation_tx);
SetIsAllocated();
} }
ABSL_INTERNAL_CATCH_ANY {
AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
ABSL_INTERNAL_RETHROW;
}
// Destroy elements in old backing store.
inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
storage_view.size);
DeallocateIfAllocated();
AcquireAllocatedData(&allocation_tx);
SetIsAllocated();
AddSize(1); AddSize(1);
return *last_ptr; return *last_ptr;
} }
......
...@@ -416,6 +416,7 @@ cc_test( ...@@ -416,6 +416,7 @@ cc_test(
":flag", ":flag",
":parse", ":parse",
":reflection", ":reflection",
":usage_internal",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
"//absl/base:scoped_set_env", "//absl/base:scoped_set_env",
"//absl/strings", "//absl/strings",
......
...@@ -366,6 +366,7 @@ absl_cc_test( ...@@ -366,6 +366,7 @@ absl_cc_test(
absl::flags absl::flags
absl::flags_parse absl::flags_parse
absl::flags_reflection absl::flags_reflection
absl::flags_usage_internal
absl::raw_logging_internal absl::raw_logging_internal
absl::scoped_set_env absl::scoped_set_env
absl::span absl::span
......
...@@ -66,17 +66,39 @@ void FlagsHelp(std::ostream& out, absl::string_view filter, ...@@ -66,17 +66,39 @@ void FlagsHelp(std::ostream& out, absl::string_view filter,
int HandleUsageFlags(std::ostream& out, int HandleUsageFlags(std::ostream& out,
absl::string_view program_usage_message); absl::string_view program_usage_message);
// --------------------------------------------------------------------
// Globals representing usage reporting flags
enum class HelpMode {
kNone,
kImportant,
kShort,
kFull,
kPackage,
kMatch,
kVersion,
kOnlyCheckArgs
};
// Returns substring to filter help output (--help=substr argument)
std::string GetFlagsHelpMatchSubstr();
// Returns the requested help mode.
HelpMode GetFlagsHelpMode();
// Returns the requested help format.
HelpFormat GetFlagsHelpFormat();
// These are corresponding setters to the attributes above.
void SetFlagsHelpMatchSubstr(absl::string_view);
void SetFlagsHelpMode(HelpMode);
void SetFlagsHelpFormat(HelpFormat);
// 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);
} // namespace flags_internal } // namespace flags_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
ABSL_DECLARE_FLAG(bool, help);
ABSL_DECLARE_FLAG(bool, helpfull);
ABSL_DECLARE_FLAG(bool, helpshort);
ABSL_DECLARE_FLAG(bool, helppackage);
ABSL_DECLARE_FLAG(bool, version);
ABSL_DECLARE_FLAG(bool, only_check_args);
ABSL_DECLARE_FLAG(std::string, helpon);
ABSL_DECLARE_FLAG(std::string, helpmatch);
#endif // ABSL_FLAGS_INTERNAL_USAGE_H_ #endif // ABSL_FLAGS_INTERNAL_USAGE_H_
...@@ -87,6 +87,11 @@ class UsageReportingTest : public testing::Test { ...@@ -87,6 +87,11 @@ class UsageReportingTest : public testing::Test {
default_config.normalize_filename = &NormalizeFileName; default_config.normalize_filename = &NormalizeFileName;
absl::SetFlagsUsageConfig(default_config); absl::SetFlagsUsageConfig(default_config);
} }
~UsageReportingTest() override {
flags::SetFlagsHelpMode(flags::HelpMode::kNone);
flags::SetFlagsHelpMatchSubstr("");
flags::SetFlagsHelpFormat(flags::HelpFormat::kHumanReadable);
}
private: private:
absl::FlagSaver flag_saver_; absl::FlagSaver flag_saver_;
...@@ -191,6 +196,10 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { ...@@ -191,6 +196,10 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) {
Some more help. Some more help.
Even more long long long long long long long long long long long long help Even more long long long long long long long long long long long long help
message.); default: ""; message.); default: "";
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.
)"; )";
std::stringstream test_buf_01; std::stringstream test_buf_01;
...@@ -214,7 +223,11 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { ...@@ -214,7 +223,11 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) {
EXPECT_EQ(test_buf_04.str(), EXPECT_EQ(test_buf_04.str(),
R"(usage_test: Custom usage message R"(usage_test: Custom usage message
No modules matched: use -helpfull No flags matched.
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.
)"); )");
std::stringstream test_buf_05; std::stringstream test_buf_05;
...@@ -226,12 +239,8 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { ...@@ -226,12 +239,8 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) {
absl::StartsWith(test_out_str, "usage_test: Custom usage message")); absl::StartsWith(test_out_str, "usage_test: Custom usage message"));
EXPECT_TRUE(absl::StrContains( EXPECT_TRUE(absl::StrContains(
test_out_str, "Flags from absl/flags/internal/usage_test.cc:")); test_out_str, "Flags from absl/flags/internal/usage_test.cc:"));
EXPECT_TRUE(absl::StrContains(test_out_str,
"Flags from absl/flags/internal/usage.cc:"));
EXPECT_TRUE( EXPECT_TRUE(
absl::StrContains(test_out_str, "-usage_reporting_test_flag_01 ")); absl::StrContains(test_out_str, "-usage_reporting_test_flag_01 "));
EXPECT_TRUE(absl::StrContains(test_out_str, "-help (show help"))
<< test_out_str;
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
...@@ -244,7 +253,40 @@ TEST_F(UsageReportingTest, TestNoUsageFlags) { ...@@ -244,7 +253,40 @@ TEST_F(UsageReportingTest, TestNoUsageFlags) {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
absl::SetFlag(&FLAGS_helpshort, true); flags::SetFlagsHelpMode(flags::HelpMode::kShort);
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
EXPECT_EQ(test_buf.str(),
R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
default: 101;
--usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
default: false;
--usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
default: 1.03;
--usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
default: 1000000000000004;
--usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
default: UDT{};
--usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
Some more help.
Even more long long long long long long long long long long long long help
message.); default: "";
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.
)");
}
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
flags::SetFlagsHelpMode(flags::HelpMode::kImportant);
std::stringstream test_buf; std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
...@@ -267,13 +309,42 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { ...@@ -267,13 +309,42 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
Some more help. Some more help.
Even more long long long long long long long long long long long long help Even more long long long long long long long long long long long long help
message.); default: ""; message.); default: "";
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.
)");
}
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_help_one_flag) {
flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
flags::SetFlagsHelpMatchSubstr("usage_reporting_test_flag_06");
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
EXPECT_EQ(test_buf.str(),
R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
Some more help.
Even more long long long long long long long long long long long long help
message.); default: "";
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.
)"); )");
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_help) { TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
absl::SetFlag(&FLAGS_help, true); flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
flags::SetFlagsHelpMatchSubstr("test_flag");
std::stringstream test_buf; std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
...@@ -297,14 +368,16 @@ TEST_F(UsageReportingTest, TestUsageFlag_help) { ...@@ -297,14 +368,16 @@ TEST_F(UsageReportingTest, TestUsageFlag_help) {
Even more long long long long long long long long long long long long help Even more long long long long long long long long long long long long help
message.); default: ""; message.); default: "";
Try --helpfull to get a list of all flags. 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.
)"); )");
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
absl::SetFlag(&FLAGS_helppackage, true); flags::SetFlagsHelpMode(flags::HelpMode::kPackage);
std::stringstream test_buf; std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1); EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
...@@ -328,14 +401,16 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { ...@@ -328,14 +401,16 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
Even more long long long long long long long long long long long long help Even more long long long long long long long long long long long long help
message.); default: ""; message.); default: "";
Try --helpfull to get a list of all flags. 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.
)"); )");
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_version) { TEST_F(UsageReportingTest, TestUsageFlag_version) {
absl::SetFlag(&FLAGS_version, true); flags::SetFlagsHelpMode(flags::HelpMode::kVersion);
std::stringstream test_buf; std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0); EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
...@@ -349,7 +424,7 @@ TEST_F(UsageReportingTest, TestUsageFlag_version) { ...@@ -349,7 +424,7 @@ TEST_F(UsageReportingTest, TestUsageFlag_version) {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) { TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) {
absl::SetFlag(&FLAGS_only_check_args, true); flags::SetFlagsHelpMode(flags::HelpMode::kOnlyCheckArgs);
std::stringstream test_buf; std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0); EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
...@@ -359,17 +434,22 @@ TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) { ...@@ -359,17 +434,22 @@ TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_helpon) { TEST_F(UsageReportingTest, TestUsageFlag_helpon) {
absl::SetFlag(&FLAGS_helpon, "bla-bla"); flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
flags::SetFlagsHelpMatchSubstr("/bla-bla.");
std::stringstream test_buf_01; std::stringstream test_buf_01;
EXPECT_EQ(flags::HandleUsageFlags(test_buf_01, kTestUsageMessage), 1); EXPECT_EQ(flags::HandleUsageFlags(test_buf_01, kTestUsageMessage), 1);
EXPECT_EQ(test_buf_01.str(), EXPECT_EQ(test_buf_01.str(),
R"(usage_test: Custom usage message R"(usage_test: Custom usage message
No modules matched: use -helpfull No flags matched.
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.
)"); )");
absl::SetFlag(&FLAGS_helpon, "usage_test"); flags::SetFlagsHelpMatchSubstr("/usage_test.");
std::stringstream test_buf_02; std::stringstream test_buf_02;
EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), 1); EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), 1);
...@@ -392,6 +472,10 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpon) { ...@@ -392,6 +472,10 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpon) {
Some more help. Some more help.
Even more long long long long long long long long long long long long help Even more long long long long long long long long long long long long help
message.); default: ""; message.); default: "";
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.
)"); )");
} }
......
...@@ -713,6 +713,11 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], ...@@ -713,6 +713,11 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
std::tie(flag, is_negative) = LocateFlag(flag_name); std::tie(flag, is_negative) = LocateFlag(flag_name);
if (flag == nullptr) { if (flag == nullptr) {
// Usage flags are not modeled as Abseil flags. Locate them separately.
if (flags_internal::DeduceUsageFlags(flag_name, value)) {
continue;
}
if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) { if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
undefined_flag_names.emplace_back(arg_from_argv, undefined_flag_names.emplace_back(arg_from_argv,
std::string(flag_name)); std::string(flag_name));
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "absl/flags/declare.h" #include "absl/flags/declare.h"
#include "absl/flags/flag.h" #include "absl/flags/flag.h"
#include "absl/flags/internal/parse.h" #include "absl/flags/internal/parse.h"
#include "absl/flags/internal/usage.h"
#include "absl/flags/reflection.h" #include "absl/flags/reflection.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
...@@ -207,6 +208,9 @@ namespace flags = absl::flags_internal; ...@@ -207,6 +208,9 @@ namespace flags = absl::flags_internal;
using testing::ElementsAreArray; using testing::ElementsAreArray;
class ParseTest : public testing::Test { class ParseTest : public testing::Test {
public:
~ParseTest() override { flags::SetFlagsHelpMode(flags::HelpMode::kNone); }
private: private:
absl::FlagSaver flag_saver_; absl::FlagSaver flag_saver_;
}; };
...@@ -851,7 +855,7 @@ TEST_F(ParseTest, TestIgnoreUndefinedFlags) { ...@@ -851,7 +855,7 @@ TEST_F(ParseTest, TestIgnoreUndefinedFlags) {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(ParseDeathTest, TestHelpFlagHandling) { TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) {
const char* in_args1[] = { const char* in_args1[] = {
"testbin", "testbin",
"--help", "--help",
...@@ -870,11 +874,38 @@ TEST_F(ParseDeathTest, TestHelpFlagHandling) { ...@@ -870,11 +874,38 @@ TEST_F(ParseDeathTest, TestHelpFlagHandling) {
flags::UsageFlagsAction::kIgnoreUsage, flags::UsageFlagsAction::kIgnoreUsage,
flags::OnUndefinedFlag::kAbortIfUndefined); flags::OnUndefinedFlag::kAbortIfUndefined);
EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(ParseDeathTest, TestSubstringHelpFlagHandling) {
const char* in_args1[] = {
"testbin",
"--help=abcd",
};
auto out_args1 = flags::ParseCommandLineImpl(
2, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
flags::UsageFlagsAction::kIgnoreUsage,
flags::OnUndefinedFlag::kAbortIfUndefined);
EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kMatch);
EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd");
const char* in_args2[] = {"testbin", "--help", "some_positional_arg"};
auto out_args2 = flags::ParseCommandLineImpl(
3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
flags::UsageFlagsAction::kIgnoreUsage,
flags::OnUndefinedFlag::kAbortIfUndefined);
EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
}
// --------------------------------------------------------------------
TEST_F(ParseTest, WasPresentOnCommandLine) { TEST_F(ParseTest, WasPresentOnCommandLine) {
const char* in_args1[] = { const char* in_args1[] = {
"testbin", "arg1", "--bool_flag", "testbin", "arg1", "--bool_flag",
......
...@@ -32,8 +32,6 @@ ABSL_FLAG(int, int_flag, 1, "int_flag help"); ...@@ -32,8 +32,6 @@ ABSL_FLAG(int, int_flag, 1, "int_flag help");
ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help"); ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help"); ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
ABSL_DECLARE_FLAG(bool, help);
namespace { namespace {
namespace flags = absl::flags_internal; namespace flags = absl::flags_internal;
...@@ -66,12 +64,9 @@ TEST_F(ReflectionTest, TestFindCommandLineFlag) { ...@@ -66,12 +64,9 @@ TEST_F(ReflectionTest, TestFindCommandLineFlag) {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
TEST_F(ReflectionTest, TestGetAllFlags) { TEST_F(ReflectionTest, TestGetAllFlags) {
(void)absl::GetFlag(FLAGS_help); // Force linking of usage flags.
auto all_flags = absl::GetAllFlags(); auto all_flags = absl::GetAllFlags();
EXPECT_NE(all_flags.find("int_flag"), all_flags.end()); EXPECT_NE(all_flags.find("int_flag"), all_flags.end());
EXPECT_EQ(all_flags.find("bool_retired_flag"), all_flags.end()); EXPECT_EQ(all_flags.find("bool_retired_flag"), all_flags.end());
EXPECT_NE(all_flags.find("help"), all_flags.end());
EXPECT_EQ(all_flags.find("some_undefined_flag"), all_flags.end()); EXPECT_EQ(all_flags.find("some_undefined_flag"), all_flags.end());
std::vector<absl::string_view> flag_names_first_attempt; std::vector<absl::string_view> flag_names_first_attempt;
......
...@@ -36,6 +36,13 @@ using Payloads = absl::InlinedVector<Payload, 1>; ...@@ -36,6 +36,13 @@ using Payloads = absl::InlinedVector<Payload, 1>;
// Reference-counted representation of Status data. // Reference-counted representation of Status data.
struct StatusRep { struct StatusRep {
StatusRep(absl::StatusCode code, std::string message,
std::unique_ptr<status_internal::Payloads> payloads)
: ref(int32_t{1}),
code(code),
message(std::move(message)),
payloads(std::move(payloads)) {}
std::atomic<int32_t> ref; std::atomic<int32_t> ref;
absl::StatusCode code; absl::StatusCode code;
std::string message; std::string message;
......
...@@ -209,11 +209,8 @@ void Status::UnrefNonInlined(uintptr_t rep) { ...@@ -209,11 +209,8 @@ void Status::UnrefNonInlined(uintptr_t rep) {
uintptr_t Status::NewRep(absl::StatusCode code, absl::string_view msg, uintptr_t Status::NewRep(absl::StatusCode code, absl::string_view msg,
std::unique_ptr<status_internal::Payloads> payloads) { std::unique_ptr<status_internal::Payloads> payloads) {
status_internal::StatusRep* rep = new status_internal::StatusRep; status_internal::StatusRep* rep = new status_internal::StatusRep(
rep->ref.store(1, std::memory_order_relaxed); code, std::string(msg.data(), msg.size()), std::move(payloads));
rep->code = code;
rep->message.assign(msg.data(), msg.size());
rep->payloads = std::move(payloads);
return PointerToRep(rep); return PointerToRep(rep);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment