From a9a49560208484f1f99efdde889da6147e8722fe Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 29 Jan 2021 12:09:30 -0800 Subject: Export of internal Abseil changes -- c68f1886f5e8fd90eb0c2d2e68feaf00a7cdacda by CJ Johnson : Introduce absl::Cleanup to the OSS repo PiperOrigin-RevId: 354583156 -- 17030cf388e10f7eb959e3e566326d1072ce392e by Abseil Team : Internal change only PiperOrigin-RevId: 354574953 -- e979d7236d4f3252e79ddda6739b67a9a326bf6d by CJ Johnson : Internal change PiperOrigin-RevId: 354545297 -- 7ea02b3783f7f49ef97d86a8f6580a19cc57df14 by Abseil Team : Pre-allocate memory for vectors where the size is known. PiperOrigin-RevId: 354344576 -- 9246c7cb11f1d6444f79ebe25acc69a8a9b870e0 by Matt Kulukundis : Add support for Elbrus 2000 (e2k) Import of https://github.com/abseil/abseil-cpp/pull/889 PiperOrigin-RevId: 354344013 -- 0fc93d359cc1fb307552e917b37b7b2e7eed822f by Abseil Team : Integrate CordRepRing logic into cord (but do not enable it) PiperOrigin-RevId: 354312238 -- eda05622f7da71466723acb33403f783529df24b by Abseil Team : Protect ignore diagnostic with "__has_warning". PiperOrigin-RevId: 354112334 -- 47716c5d8fb10efa4fdd801d28bac414c6f8ec32 by Abseil Team : Rearrange InlinedVector copy constructor and destructor to treat a few special cases inline and then tail-call a non-inlined routine for the rest. In particular, we optimize for empty vectors in both cases. Added a couple of benchmarks that copy either an InlVec or an InlVec>. Speed difference: ``` BM_CopyTrivial/0 0.92ns +- 0% 0.47ns +- 0% -48.91% (p=0.000 n=11+12) BM_CopyTrivial/1 0.92ns +- 0% 1.15ns +- 0% +25.00% (p=0.000 n=10+9) BM_CopyTrivial/8 8.57ns +- 0% 10.72ns +- 1% +25.16% (p=0.000 n=10+12) BM_CopyNonTrivial/0 3.21ns +- 0% 0.70ns +- 0% -78.23% (p=0.000 n=12+10) BM_CopyNonTrivial/1 5.88ns +- 1% 5.51ns +- 0% -6.28% (p=0.000 n=10+8) BM_CopyNonTrivial/8 21.5ns +- 1% 15.2ns +- 2% -29.23% (p=0.000 n=12+12) ``` Note: the slowdowns are a few cycles which is expected given the procedure call added in that case. We decided this is a good tradeoff given the code size reductions and the more significant speedups for empty vectors. Size difference (as measured by nm): ``` BM_CopyTrivial from 1048 bytes to 326 bytes. BM_CopyNonTrivial from 749 bytes to 470 bytes. ``` Code size for a large binary drops by ~500KB (from 349415719 to 348906015 348906191). All of the benchmarks that showed a significant difference: Ones that improve with this CL: ``` BM_CopyNonTrivial/0 3.21ns +- 0% 0.70ns +- 0% -78.23% (p=0.000 n=12+10) BM_InlinedVectorFillString/0 0.93ns +- 0% 0.24ns +- 0% -74.19% (p=0.000 n=12+10) BM_InlinedVectorAssignments/1 10.5ns +- 0% 4.1ns +- 0% -60.64% (p=0.000 n=11+10) BM_InlinedVectorAssignments/2 10.7ns +- 0% 4.4ns +- 0% -59.08% (p=0.000 n=11+11) BM_CopyTrivial/0 0.92ns +- 0% 0.47ns +- 0% -48.91% (p=0.000 n=11+12) BM_CopyNonTrivial/8 21.5ns +- 1% 15.2ns +- 2% -29.23% (p=0.000 n=12+12) BM_StdVectorEmpty 0.47ns +- 1% 0.35ns +- 0% -24.73% (p=0.000 n=12+12) BM_StdVectorSize 0.46ns +- 2% 0.35ns +- 0% -24.32% (p=0.000 n=12+12) BM_SwapElements/0 3.44ns +- 0% 2.76ns +- 1% -19.83% (p=0.000 n=11+11) BM_InlinedVectorFillRange/256 20.7ns +- 1% 17.8ns +- 0% -14.08% (p=0.000 n=12+9) BM_CopyNonTrivial/1 5.88ns +- 1% 5.51ns +- 0% -6.28% (p=0.000 n=10+8) BM_SwapElements/1 4.19ns +- 0% 3.95ns +- 1% -5.63% (p=0.000 n=11+12) BM_SwapElements/1 4.18ns +- 0% 3.99ns +- 0% -4.70% (p=0.000 n=9+11) BM_SwapElements/0 2.41ns +- 0% 2.31ns +- 0% -4.45% (p=0.000 n=12+12) BM_InlinedVectorFillRange/64 8.25ns +- 0% 8.04ns +- 0% -2.51% (p=0.000 n=12+11) BM_SwapElements/1 82.4ns +- 0% 81.5ns +- 0% -1.06% (p=0.000 n=12+12) ``` Ones that get worse with this CL: ``` BM_CopyTrivial/1 0.92ns +- 0% 1.15ns +- 0% +25.00% (p=0.000 n=10+9) BM_CopyTrivial/8 8.57ns +- 0% 10.72ns +- 1% +25.16% (p=0.000 n=10+12) BM_SwapElements/512 1.48ns +- 1% 1.66ns +- 1% +11.88% (p=0.000 n=12+12) BM_InlinedVectorFillString/1 11.5ns +- 0% 12.8ns +- 1% +11.62% (p=0.000 n=12+11) BM_SwapElements/64 1.48ns +- 2% 1.66ns +- 1% +11.66% (p=0.000 n=12+11) BM_SwapElements/1k 1.48ns +- 1% 1.65ns +- 2% +11.32% (p=0.000 n=12+12) BM_SwapElements/512 1.48ns +- 2% 1.58ns +- 4% +6.62% (p=0.000 n=11+12) BM_SwapElements/1k 1.49ns +- 2% 1.58ns +- 3% +6.05% (p=0.000 n=12+12) BM_SwapElements/64 1.48ns +- 2% 1.57ns +- 4% +6.04% (p=0.000 n=11+12) BM_InlinedVectorFillRange/1 4.81ns +- 0% 5.05ns +- 0% +4.83% (p=0.000 n=11+11) BM_InlinedVectorFillString/8 79.4ns +- 1% 83.1ns +- 1% +4.64% (p=0.000 n=10+12) BM_StdVectorFillString/1 16.3ns +- 0% 16.6ns +- 0% +2.13% (p=0.000 n=11+8) ``` PiperOrigin-RevId: 353906786 -- 8e26518b3cec9c598e5e9573c46c3bd1b03a67ef by Abseil Team : Internal change PiperOrigin-RevId: 353737330 -- f206ae0983e58c9904ed8b8f05f9caf564a446be by Matt Kulukundis : Import of CCTZ from GitHub. PiperOrigin-RevId: 353682256 GitOrigin-RevId: c68f1886f5e8fd90eb0c2d2e68feaf00a7cdacda Change-Id: I5790c1036c4f543c701d1039848fabf7ae881ad8 --- absl/cleanup/cleanup.h | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 absl/cleanup/cleanup.h (limited to 'absl/cleanup/cleanup.h') diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h new file mode 100644 index 00000000..eba04b33 --- /dev/null +++ b/absl/cleanup/cleanup.h @@ -0,0 +1,129 @@ +// Copyright 2021 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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: cleanup.h +// ----------------------------------------------------------------------------- +// +// `absl::Cleanup` implements the scope guard idiom, invoking `operator()() &&` +// on the callback it was constructed with, on scope exit. +// +// Example: +// +// ``` +// void CopyGoodData(const char* input_path, const char* output_path) { +// FILE* in_file = fopen(input_path, "r"); +// FILE* out_file = fopen(output_path, "w"); +// if (in_file == nullptr || out_file == nullptr) return; +// +// // C++17 style using class template argument deduction +// absl::Cleanup in_closer = [&in_file] { fclose(in_file); }; +// +// // C++11 style using the factory function +// auto out_closer = absl::MakeCleanup([&out_file] { fclose(out_file); }); +// +// // `fclose` will be called on all exit paths by the cleanup instances +// +// Data data; +// while (ReadData(in_file, &data)) { +// if (data.IsBad()) { +// LOG(ERROR) << "Found bad data."; +// return; // `in_closer` and `out_closer` will call their callbacks +// } +// SaveData(out_file, &data); +// } +// return; // `in_closer` and `out_closer` will call their callbacks +// } +// ``` +// +// `std::move(cleanup).Invoke()` will execute the callback early, before +// destruction, and prevent the callback from executing in the destructor. +// +// Alternatively, `std::move(cleanup).Cancel()` will prevent the callback from +// ever executing at all. +// +// Once a cleanup object has been `std::move(...)`-ed, it may not be used again. + +#ifndef ABSL_CLEANUP_CLEANUP_H_ +#define ABSL_CLEANUP_CLEANUP_H_ + +#include + +#include "absl/base/config.h" +#include "absl/base/macros.h" +#include "absl/cleanup/internal/cleanup.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +template +class ABSL_MUST_USE_RESULT Cleanup { + static_assert(cleanup_internal::WasDeduced(), + "Explicit template parameters are not supported."); + + static_assert(cleanup_internal::ReturnsVoid(), + "Callbacks that return values are not supported."); + + public: + Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT + + Cleanup(Cleanup&& other) : storage_(std::move(other.storage_)) {} + + void Cancel() && { + ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged()); + storage_.DisengageCallback(); + } + + void Invoke() && { + ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged()); + storage_.DisengageCallback(); + storage_.InvokeCallback(); + } + + ~Cleanup() { + if (storage_.IsCallbackEngaged()) { + storage_.InvokeCallback(); + } + } + + private: + cleanup_internal::Storage storage_; +}; + +// `auto c = absl::MakeCleanup(/* callback */);` +// +// C++11 type deduction API for creating an instance of `absl::Cleanup`. +template +absl::Cleanup MakeCleanup(Callback callback) { + static_assert(cleanup_internal::WasDeduced(), + "Explicit template parameters are not supported."); + + static_assert(cleanup_internal::ReturnsVoid(), + "Callbacks that return values are not supported."); + + return {std::move(callback)}; +} + +// `absl::Cleanup c = /* callback */;` +// +// C++17 type deduction API for creating an instance of `absl::Cleanup`. +#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) +template +Cleanup(Callback callback) -> Cleanup; +#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_CLEANUP_CLEANUP_H_ -- cgit v1.2.3 From 184d2f8364bcb05e413ec4c72cad0cf86e712d1c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Sat, 30 Jan 2021 06:20:07 -0800 Subject: Export of internal Abseil changes -- 8c77b14bdee3f4cafb8ba520d4d050b15a949fd4 by Derek Mauro : Fix absl::Cleanup usage example PiperOrigin-RevId: 354702001 -- 10365da7a0aacaa0c4774a4b618a76dff328611b by CJ Johnson : Swap the order of the C++11 and C++17 interfaces for absl::Cleanup to mirror the order used in the comment example PiperOrigin-RevId: 354675180 GitOrigin-RevId: 8c77b14bdee3f4cafb8ba520d4d050b15a949fd4 Change-Id: Ia2054b725ed737ff9e557cb3d973de7c34bc51b0 --- absl/cleanup/cleanup.h | 42 +++++++-------- absl/cleanup/cleanup_test.cc | 117 ++++++++++++++++++++++++---------------- absl/cleanup/internal/cleanup.h | 2 + 3 files changed, 95 insertions(+), 66 deletions(-) (limited to 'absl/cleanup/cleanup.h') diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h index eba04b33..f606b3f4 100644 --- a/absl/cleanup/cleanup.h +++ b/absl/cleanup/cleanup.h @@ -24,36 +24,36 @@ // ``` // void CopyGoodData(const char* input_path, const char* output_path) { // FILE* in_file = fopen(input_path, "r"); -// FILE* out_file = fopen(output_path, "w"); -// if (in_file == nullptr || out_file == nullptr) return; +// if (in_file == nullptr) return; // // // C++17 style using class template argument deduction -// absl::Cleanup in_closer = [&in_file] { fclose(in_file); }; +// absl::Cleanup in_closer = [in_file] { fclose(in_file); }; // -// // C++11 style using the factory function -// auto out_closer = absl::MakeCleanup([&out_file] { fclose(out_file); }); +// FILE* out_file = fopen(output_path, "w"); +// if (out_file == nullptr) return; // `in_closer` will run // -// // `fclose` will be called on all exit paths by the cleanup instances +// // C++11 style using the factory function +// auto out_closer = absl::MakeCleanup([out_file] { fclose(out_file); }); // // Data data; // while (ReadData(in_file, &data)) { // if (data.IsBad()) { // LOG(ERROR) << "Found bad data."; -// return; // `in_closer` and `out_closer` will call their callbacks +// return; // `in_closer` and `out_closer` will run // } // SaveData(out_file, &data); // } -// return; // `in_closer` and `out_closer` will call their callbacks +// +// // `in_closer` and `out_closer` will run // } // ``` // -// `std::move(cleanup).Invoke()` will execute the callback early, before -// destruction, and prevent the callback from executing in the destructor. +// Methods: // -// Alternatively, `std::move(cleanup).Cancel()` will prevent the callback from -// ever executing at all. +// `std::move(cleanup).Cancel()` will prevent the callback from executing. // -// Once a cleanup object has been `std::move(...)`-ed, it may not be used again. +// `std::move(cleanup).Invoke()` will execute the callback early, before +// destruction, and prevent the callback from executing in the destructor. #ifndef ABSL_CLEANUP_CLEANUP_H_ #define ABSL_CLEANUP_CLEANUP_H_ @@ -101,6 +101,14 @@ class ABSL_MUST_USE_RESULT Cleanup { cleanup_internal::Storage storage_; }; +// `absl::Cleanup c = /* callback */;` +// +// C++17 type deduction API for creating an instance of `absl::Cleanup`. +#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) +template +Cleanup(Callback callback) -> Cleanup; +#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) + // `auto c = absl::MakeCleanup(/* callback */);` // // C++11 type deduction API for creating an instance of `absl::Cleanup`. @@ -115,14 +123,6 @@ absl::Cleanup MakeCleanup(Callback callback) { return {std::move(callback)}; } -// `absl::Cleanup c = /* callback */;` -// -// C++17 type deduction API for creating an instance of `absl::Cleanup`. -#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) -template -Cleanup(Callback callback) -> Cleanup; -#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) - ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/cleanup/cleanup_test.cc b/absl/cleanup/cleanup_test.cc index 34e3bfad..792595d6 100644 --- a/absl/cleanup/cleanup_test.cc +++ b/absl/cleanup/cleanup_test.cc @@ -27,8 +27,8 @@ namespace { using Tag = absl::cleanup_internal::Tag; template -void AssertSameType() { - static_assert(std::is_same::value, ""); +constexpr bool IsSame() { + return (std::is_same::value); } struct IdentityFactory { @@ -88,27 +88,31 @@ template struct CleanupTest : public ::testing::Test {}; TYPED_TEST_SUITE(CleanupTest, CleanupTestParams); -bool function_pointer_called = false; -void FunctionPointerFunction() { function_pointer_called = true; } +bool fn_ptr_called = false; +void FnPtrFunction() { fn_ptr_called = true; } TYPED_TEST(CleanupTest, FactoryProducesCorrectType) { { auto callback = TypeParam::AsCallback([] {}); auto cleanup = absl::MakeCleanup(std::move(callback)); - AssertSameType, decltype(cleanup)>(); + static_assert( + IsSame, decltype(cleanup)>(), + ""); } { - auto cleanup = absl::MakeCleanup(&FunctionPointerFunction); + auto cleanup = absl::MakeCleanup(&FnPtrFunction); - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } { - auto cleanup = absl::MakeCleanup(FunctionPointerFunction); + auto cleanup = absl::MakeCleanup(FnPtrFunction); - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } } @@ -118,19 +122,23 @@ TYPED_TEST(CleanupTest, CTADProducesCorrectType) { auto callback = TypeParam::AsCallback([] {}); absl::Cleanup cleanup = std::move(callback); - AssertSameType, decltype(cleanup)>(); + static_assert( + IsSame, decltype(cleanup)>(), + ""); } { - absl::Cleanup cleanup = &FunctionPointerFunction; + absl::Cleanup cleanup = &FnPtrFunction; - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } { - absl::Cleanup cleanup = FunctionPointerFunction; + absl::Cleanup cleanup = FnPtrFunction; - AssertSameType, decltype(cleanup)>(); + static_assert(IsSame, decltype(cleanup)>(), + ""); } } @@ -140,7 +148,8 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { auto factory_cleanup = absl::MakeCleanup(callback); absl::Cleanup deduction_cleanup = callback; - AssertSameType(); + static_assert( + IsSame(), ""); } { @@ -148,7 +157,8 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { absl::MakeCleanup(FunctorClassFactory::AsCallback([] {})); absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {}); - AssertSameType(); + static_assert( + IsSame(), ""); } { @@ -156,21 +166,24 @@ TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { absl::MakeCleanup(StdFunctionFactory::AsCallback([] {})); absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {}); - AssertSameType(); + static_assert( + IsSame(), ""); } { - auto factory_cleanup = absl::MakeCleanup(&FunctionPointerFunction); - absl::Cleanup deduction_cleanup = &FunctionPointerFunction; + auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction); + absl::Cleanup deduction_cleanup = &FnPtrFunction; - AssertSameType(); + static_assert( + IsSame(), ""); } { - auto factory_cleanup = absl::MakeCleanup(FunctionPointerFunction); - absl::Cleanup deduction_cleanup = FunctionPointerFunction; + auto factory_cleanup = absl::MakeCleanup(FnPtrFunction); + absl::Cleanup deduction_cleanup = FnPtrFunction; - AssertSameType(); + static_assert( + IsSame(), ""); } } #endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) @@ -179,62 +192,76 @@ TYPED_TEST(CleanupTest, BasicUsage) { bool called = false; { - EXPECT_FALSE(called); - auto cleanup = absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); - - EXPECT_FALSE(called); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback } - EXPECT_TRUE(called); + EXPECT_TRUE(called); // Destructor should invoke the callback } TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) { - function_pointer_called = false; + fn_ptr_called = false; { - EXPECT_FALSE(function_pointer_called); - - auto cleanup = - absl::MakeCleanup(TypeParam::AsCallback(&FunctionPointerFunction)); - - EXPECT_FALSE(function_pointer_called); + auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction)); + EXPECT_FALSE(fn_ptr_called); // Constructor shouldn't invoke the callback } - EXPECT_TRUE(function_pointer_called); + EXPECT_TRUE(fn_ptr_called); // Destructor should invoke the callback } TYPED_TEST(CleanupTest, Cancel) { bool called = false; { - EXPECT_FALSE(called); - auto cleanup = absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); - std::move(cleanup).Cancel(); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback - EXPECT_FALSE(called); + std::move(cleanup).Cancel(); + EXPECT_FALSE(called); // Cancel shouldn't invoke the callback } - EXPECT_FALSE(called); + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback } TYPED_TEST(CleanupTest, Invoke) { bool called = false; { - EXPECT_FALSE(called); - auto cleanup = absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + std::move(cleanup).Invoke(); + EXPECT_TRUE(called); // Invoke should invoke the callback + + called = false; // Reset tracker before destructor runs + } + + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback +} + +TYPED_TEST(CleanupTest, Move) { + bool called = false; + + { + auto moved_from_cleanup = + absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); + EXPECT_FALSE(called); // Constructor shouldn't invoke the callback + + { + auto moved_to_cleanup = std::move(moved_from_cleanup); + EXPECT_FALSE(called); // Move shouldn't invoke the callback + } + + EXPECT_TRUE(called); // Destructor should invoke the callback - EXPECT_TRUE(called); + called = false; // Reset tracker before destructor runs } - EXPECT_TRUE(called); + EXPECT_FALSE(called); // Destructor shouldn't invoke the callback } } // namespace diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h index a126ff30..8fbca5bd 100644 --- a/absl/cleanup/internal/cleanup.h +++ b/absl/cleanup/internal/cleanup.h @@ -43,6 +43,8 @@ constexpr bool ReturnsVoid() { template class Storage { public: + Storage() = delete; + explicit Storage(Callback callback) : engaged_(true), callback_(std::move(callback)) {} -- cgit v1.2.3 From 20869f89edbc38139f46bdc49c8b6c3a1f7bee4c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 1 Feb 2021 14:09:21 -0800 Subject: Export of internal Abseil changes -- cea62ebc5d31c62aabcb94c066d9be506f34baf6 by Abseil Team : Fix typo in `Cord::EndsWith()` docs PiperOrigin-RevId: 355023067 -- f89225a55476478ec167be50dea543f5414836f9 by Abseil Team : Add set_cordz_info() and get_cordz_info() methods to InlineData This change has preparations for future (optional) integration of CordzInfo sampling data into Cord's InlineData for non inlined cords. PiperOrigin-RevId: 354965340 -- 324057574aeb697bd3327cb905eb5bca16ade768 by Abseil Team : Fix two comment typos. PiperOrigin-RevId: 354952568 -- 5bb93ca3d57ead3633e1efde4aa28718987ef64f by CJ Johnson : Clarify doc comment for absl::Cleanup by using absl::Status return type and clarify the engaged state by surfacing the initial value in the public header. PiperOrigin-RevId: 354935253 -- ec95424594b24a1aec9bf7972b2355f37285506a by Abseil Team : Remove `preserve_most` attribute from CordRep::Destroy() PiperOrigin-RevId: 354921927 GitOrigin-RevId: cea62ebc5d31c62aabcb94c066d9be506f34baf6 Change-Id: Ibe1d66197db7ce9554594e07b1c6e7c6dea3c9da --- absl/cleanup/cleanup.h | 51 +++++++++++++++++++++-------------- absl/cleanup/internal/cleanup.h | 10 +++---- absl/hash/internal/wyhash_test.cc | 4 +-- absl/strings/BUILD.bazel | 1 + absl/strings/cord.h | 2 +- absl/strings/internal/cord_internal.h | 44 ++++++++++++++++-------------- 6 files changed, 64 insertions(+), 48 deletions(-) (limited to 'absl/cleanup/cleanup.h') diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h index f606b3f4..5a4bc546 100644 --- a/absl/cleanup/cleanup.h +++ b/absl/cleanup/cleanup.h @@ -16,35 +16,39 @@ // File: cleanup.h // ----------------------------------------------------------------------------- // -// `absl::Cleanup` implements the scope guard idiom, invoking `operator()() &&` -// on the callback it was constructed with, on scope exit. +// `absl::Cleanup` implements the scope guard idiom, invoking the contained +// callback's `operator()() &&` on scope exit. // // Example: // // ``` -// void CopyGoodData(const char* input_path, const char* output_path) { -// FILE* in_file = fopen(input_path, "r"); -// if (in_file == nullptr) return; +// absl::Status CopyGoodData(const char* source_path, const char* sink_path) { +// FILE* source_file = fopen(source_path, "r"); +// if (source_file == nullptr) { +// return absl::NotFoundError("No source file"); // No cleanups execute +// } // -// // C++17 style using class template argument deduction -// absl::Cleanup in_closer = [in_file] { fclose(in_file); }; +// // C++17 style cleanup using class template argument deduction +// absl::Cleanup source_closer = [source_file] { fclose(source_file); }; // -// FILE* out_file = fopen(output_path, "w"); -// if (out_file == nullptr) return; // `in_closer` will run +// FILE* sink_file = fopen(sink_path, "w"); +// if (sink_file == nullptr) { +// return absl::NotFoundError("No sink file"); // First cleanup executes +// } // -// // C++11 style using the factory function -// auto out_closer = absl::MakeCleanup([out_file] { fclose(out_file); }); +// // C++11 style cleanup using the factory function +// auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); }); // // Data data; -// while (ReadData(in_file, &data)) { +// while (ReadData(source_file, &data)) { // if (data.IsBad()) { -// LOG(ERROR) << "Found bad data."; -// return; // `in_closer` and `out_closer` will run +// absl::Status result = absl::FailedPreconditionError("Read bad data"); +// return result; // Both cleanups execute // } -// SaveData(out_file, &data); +// SaveData(sink_file, &data); // } // -// // `in_closer` and `out_closer` will run +// return absl::OkStatus(); // Both cleanups execute // } // ``` // @@ -54,6 +58,12 @@ // // `std::move(cleanup).Invoke()` will execute the callback early, before // destruction, and prevent the callback from executing in the destructor. +// +// Usage: +// +// `absl::Cleanup` is not an interface type. It is only intended to be used +// within the body of a function. It is not a value type and instead models a +// control flow construct. Check out `defer` in Golang for something similar. #ifndef ABSL_CLEANUP_CLEANUP_H_ #define ABSL_CLEANUP_CLEANUP_H_ @@ -76,9 +86,10 @@ class ABSL_MUST_USE_RESULT Cleanup { "Callbacks that return values are not supported."); public: - Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT + Cleanup(Callback callback) // NOLINT + : storage_(std::move(callback), /*engaged=*/true) {} - Cleanup(Cleanup&& other) : storage_(std::move(other.storage_)) {} + Cleanup(Cleanup&& other) = default; void Cancel() && { ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged()); @@ -103,7 +114,7 @@ class ABSL_MUST_USE_RESULT Cleanup { // `absl::Cleanup c = /* callback */;` // -// C++17 type deduction API for creating an instance of `absl::Cleanup`. +// C++17 type deduction API for creating an instance of `absl::Cleanup` #if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) template Cleanup(Callback callback) -> Cleanup; @@ -111,7 +122,7 @@ Cleanup(Callback callback) -> Cleanup; // `auto c = absl::MakeCleanup(/* callback */);` // -// C++11 type deduction API for creating an instance of `absl::Cleanup`. +// C++11 type deduction API for creating an instance of `absl::Cleanup` template absl::Cleanup MakeCleanup(Callback callback) { static_assert(cleanup_internal::WasDeduced(), diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h index 8fbca5bd..b68e3dd3 100644 --- a/absl/cleanup/internal/cleanup.h +++ b/absl/cleanup/internal/cleanup.h @@ -45,12 +45,12 @@ class Storage { public: Storage() = delete; - explicit Storage(Callback callback) - : engaged_(true), callback_(std::move(callback)) {} + Storage(Callback callback, bool engaged) + : callback_(std::move(callback)), engaged_(engaged) {} Storage(Storage&& other) - : engaged_(absl::exchange(other.engaged_, false)), - callback_(std::move(other.callback_)) {} + : callback_(std::move(other.callback_)), + engaged_(absl::exchange(other.engaged_, false)) {} Storage(const Storage& other) = delete; @@ -67,8 +67,8 @@ class Storage { } private: - bool engaged_; Callback callback_; + bool engaged_; }; } // namespace cleanup_internal diff --git a/absl/hash/internal/wyhash_test.cc b/absl/hash/internal/wyhash_test.cc index 30dc9e34..9fb06d23 100644 --- a/absl/hash/internal/wyhash_test.cc +++ b/absl/hash/internal/wyhash_test.cc @@ -1,14 +1,14 @@ // Copyright 2020 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in cokSaltliance with the License. +// you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ikSaltlied. +// 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. diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 794cf43a..5efaf896 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -286,6 +286,7 @@ cc_library( "//absl/base:base_internal", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:endian", "//absl/base:raw_logging_internal", "//absl/base:throw_delegate", "//absl/container:compressed_tuple", diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 17341bda..aefb5e53 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -289,7 +289,7 @@ class Cord { bool StartsWith(const Cord& rhs) const; bool StartsWith(absl::string_view rhs) const; - // Cord::EndsWidth() + // Cord::EndsWith() // // Determines whether the Cord ends with the passed string data `rhs`. bool EndsWith(absl::string_view rhs) const; diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index 96502433..cda00a44 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -22,6 +22,7 @@ #include #include "absl/base/config.h" +#include "absl/base/internal/endian.h" #include "absl/base/internal/invoke.h" #include "absl/base/optimization.h" #include "absl/container/internal/compressed_tuple.h" @@ -32,6 +33,8 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { +class CordzInfo; + // Default feature enable states for cord ring buffers enum CordFeatureDefaults { kCordEnableRingBufferDefault = false, @@ -193,26 +196,7 @@ struct CordRep { // -------------------------------------------------------------------- // Memory management - // This internal routine is called from the cold path of Unref below. Keeping - // it in a separate routine allows good inlining of Unref into many profitable - // call sites. However, the call to this function can be highly disruptive to - // the register pressure in those callers. To minimize the cost to callers, we - // use a special LLVM calling convention that preserves most registers. This - // allows the call to this routine in cold paths to not disrupt the caller's - // register pressure. This calling convention is not available on all - // platforms; we intentionally allow LLVM to ignore the attribute rather than - // attempting to hardcode the list of supported platforms. -#if defined(__clang__) && !defined(__i386__) -#if !(defined(ABSL_HAVE_MEMORY_SANITIZER) || \ - defined(ABSL_HAVE_THREAD_SANITIZER) || \ - defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ - defined(UNDEFINED_BEHAVIOR_SANITIZER)) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wattributes" - __attribute__((preserve_most)) -#pragma clang diagnostic pop -#endif // *_SANITIZER -#endif + // Destroys the provided `rep`. static void Destroy(CordRep* rep); // Increments the reference count of `rep`. @@ -383,6 +367,26 @@ class InlineData { return as_tree_.cordz_info != kNullCordzInfo; } + // Returns the cordz_info sampling instance for this instance, or nullptr + // if the current instance is not sampled and does not have CordzInfo data. + // Requires the current instance to hold a tree value. + CordzInfo* cordz_info() const { + assert(is_tree()); + intptr_t info = + static_cast(absl::big_endian::ToHost64(as_tree_.cordz_info)); + assert(info & 1); + return reinterpret_cast(info - 1); + } + + // Sets the current cordz_info sampling instance for this instance, or nullptr + // if the current instance is not sampled and does not have CordzInfo data. + // Requires the current instance to hold a tree value. + void set_cordz_info(CordzInfo* cordz_info) { + assert(is_tree()); + intptr_t info = reinterpret_cast(cordz_info) | 1; + as_tree_.cordz_info = absl::big_endian::FromHost64(info); + } + // Returns a read only pointer to the character data inside this instance. // Requires the current instance to hold inline data. const char* as_chars() const { -- cgit v1.2.3 From 9c6a50fdd80bb39fabd95faeda84f04062685ff3 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 3 Feb 2021 10:18:15 -0800 Subject: Export of internal Abseil changes -- 4ff721439234e91caf6f7b772e5f554e7dd423c8 by Benjamin Barenblat : Remove endian-sensitivity from hash slow path Prior to this commit, the Abseil hash fast path was endian-agnostic, but the slow path assumed a little-endian platform. Change the slow path to be endian-correct, ensuring that values produced by the fast and slow paths are equal even on big-endian systems. PiperOrigin-RevId: 355424258 -- 7f4fe1aa4de46ad0a2ef19fa9c061fc12a7391ed by Abseil Team : Directly store CordzInfo in the InlineData data contents of InlineRep This greatly reduces the cost of coping and moving cords. Especially the move constructor and move assignment are now back to lean loads and stores without needing any CordzInfo lookups for tracked cords. PiperOrigin-RevId: 355409161 -- 3ca4ca84ed6d98f1e383ffd8d12c28876e905bb3 by Abseil Team : Add #include PiperOrigin-RevId: 355386114 -- 30b0ffad0621971b3135148fcc9e183b0dd2a6bb by Abseil Team : Optimize Cord copy constructor This change avoids double stores of the Cord copy constructor from the zero init of the InlineData / InlineRep contents followed by the assignment and inlines the copy constructor. PiperOrigin-RevId: 355287939 -- 0c043fa7b6e41ca7cefc5edc1e17ad46223e4e77 by CJ Johnson : Now that the absl::Cleanup example returns absl::Status, since we decided on absl::FailedPreconditionError, the precondition should be a positive statement and then the check should be failure to adhere to that positive statement PiperOrigin-RevId: 355216923 -- 9ed922ca5d28fe8790ec6bc0837cf39fbcc92896 by Gennadiy Rozental : Do not set mvsc linker flags for clang-cl (fixes #874) Import of https://github.com/abseil/abseil-cpp/pull/891 PiperOrigin-RevId: 355199380 GitOrigin-RevId: 4ff721439234e91caf6f7b772e5f554e7dd423c8 Change-Id: I3d9d2383549720d7a91f9108dfcd979ad6632fce --- absl/cleanup/cleanup.h | 4 +- absl/cleanup/internal/cleanup.h | 14 +++--- .../internal/unordered_map_constructor_test.h | 1 + absl/hash/BUILD.bazel | 1 + absl/hash/CMakeLists.txt | 1 + absl/hash/internal/hash.h | 51 +++++++++++++++++----- absl/strings/cord.cc | 8 +--- absl/strings/cord.h | 28 ++++++++++-- absl/strings/cord_test.cc | 4 ++ absl/strings/internal/cord_internal.h | 6 +++ 10 files changed, 90 insertions(+), 28 deletions(-) (limited to 'absl/cleanup/cleanup.h') diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h index 5a4bc546..8ebf1e9b 100644 --- a/absl/cleanup/cleanup.h +++ b/absl/cleanup/cleanup.h @@ -41,7 +41,7 @@ // // Data data; // while (ReadData(source_file, &data)) { -// if (data.IsBad()) { +// if (!data.IsGood()) { // absl::Status result = absl::FailedPreconditionError("Read bad data"); // return result; // Both cleanups execute // } @@ -87,7 +87,7 @@ class ABSL_MUST_USE_RESULT Cleanup { public: Cleanup(Callback callback) // NOLINT - : storage_(std::move(callback), /*engaged=*/true) {} + : storage_(std::move(callback), /* is_callback_engaged = */ true) {} Cleanup(Cleanup&& other) = default; diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h index b68e3dd3..b4c40737 100644 --- a/absl/cleanup/internal/cleanup.h +++ b/absl/cleanup/internal/cleanup.h @@ -45,12 +45,14 @@ class Storage { public: Storage() = delete; - Storage(Callback callback, bool engaged) - : callback_(std::move(callback)), engaged_(engaged) {} + Storage(Callback callback, bool is_callback_engaged) + : callback_(std::move(callback)), + is_callback_engaged_(is_callback_engaged) {} Storage(Storage&& other) : callback_(std::move(other.callback_)), - engaged_(absl::exchange(other.engaged_, false)) {} + is_callback_engaged_( + absl::exchange(other.is_callback_engaged_, false)) {} Storage(const Storage& other) = delete; @@ -58,9 +60,9 @@ class Storage { Storage& operator=(const Storage& other) = delete; - bool IsCallbackEngaged() const { return engaged_; } + bool IsCallbackEngaged() const { return is_callback_engaged_; } - void DisengageCallback() { engaged_ = false; } + void DisengageCallback() { is_callback_engaged_ = false; } void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS { std::move(callback_)(); @@ -68,7 +70,7 @@ class Storage { private: Callback callback_; - bool engaged_; + bool is_callback_engaged_; }; } // namespace cleanup_internal diff --git a/absl/container/internal/unordered_map_constructor_test.h b/absl/container/internal/unordered_map_constructor_test.h index 76ee95e6..3f90ad7c 100644 --- a/absl/container/internal/unordered_map_constructor_test.h +++ b/absl/container/internal/unordered_map_constructor_test.h @@ -16,6 +16,7 @@ #define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_ #include +#include #include #include "gmock/gmock.h" diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 90c6c8a8..4b2c220f 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel @@ -38,6 +38,7 @@ cc_library( deps = [ ":city", ":wyhash", + "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", "//absl/container:fixed_array", diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 6d198775..b43bfa54 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -26,6 +26,7 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} DEPS absl::city + absl::config absl::core_headers absl::endian absl::fixed_array diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index eb3471d8..7fb0af0b 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h @@ -38,7 +38,8 @@ #include #include -#include "absl/base/internal/endian.h" +#include "absl/base/config.h" +#include "absl/base/internal/unaligned_access.h" #include "absl/base/port.h" #include "absl/container/fixed_array.h" #include "absl/hash/internal/wyhash.h" @@ -804,26 +805,54 @@ class ABSL_DLL HashState : public HashStateBase { size_t len); // Reads 9 to 16 bytes from p. - // The first 8 bytes are in .first, the rest (zero padded) bytes are in - // .second. + // The least significant 8 bytes are in .first, the rest (zero padded) bytes + // are in .second. static std::pair Read9To16(const unsigned char* p, size_t len) { - uint64_t high = little_endian::Load64(p + len - 8); - return {little_endian::Load64(p), high >> (128 - len * 8)}; + uint64_t low_mem = absl::base_internal::UnalignedLoad64(p); + uint64_t high_mem = absl::base_internal::UnalignedLoad64(p + len - 8); +#ifdef ABSL_IS_LITTLE_ENDIAN + uint64_t most_significant = high_mem; + uint64_t least_significant = low_mem; +#else + uint64_t most_significant = low_mem; + uint64_t least_significant = high_mem; +#endif + return {least_significant, most_significant >> (128 - len * 8)}; } // Reads 4 to 8 bytes from p. Zero pads to fill uint64_t. static uint64_t Read4To8(const unsigned char* p, size_t len) { - return (static_cast(little_endian::Load32(p + len - 4)) - << (len - 4) * 8) | - little_endian::Load32(p); + uint32_t low_mem = absl::base_internal::UnalignedLoad32(p); + uint32_t high_mem = absl::base_internal::UnalignedLoad32(p + len - 4); +#ifdef ABSL_IS_LITTLE_ENDIAN + uint32_t most_significant = high_mem; + uint32_t least_significant = low_mem; +#else + uint32_t most_significant = low_mem; + uint32_t least_significant = high_mem; +#endif + return (static_cast(most_significant) << (len - 4) * 8) | + least_significant; } // Reads 1 to 3 bytes from p. Zero pads to fill uint32_t. static uint32_t Read1To3(const unsigned char* p, size_t len) { - return static_cast((p[0]) | // - (p[len / 2] << (len / 2 * 8)) | // - (p[len - 1] << ((len - 1) * 8))); + unsigned char mem0 = p[0]; + unsigned char mem1 = p[len / 2]; + unsigned char mem2 = p[len - 1]; +#ifdef ABSL_IS_LITTLE_ENDIAN + unsigned char significant2 = mem2; + unsigned char significant1 = mem1; + unsigned char significant0 = mem0; +#else + unsigned char significant2 = mem0; + unsigned char significant1 = mem1; + unsigned char significant0 = mem2; +#endif + return static_cast(significant0 | // + (significant1 << (len / 2 * 8)) | // + (significant2 << ((len - 1) * 8))); } ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Mix(uint64_t state, uint64_t v) { diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 39191ef5..93533757 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -495,7 +495,9 @@ void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { data_ = src.data_; if (is_tree()) { + data_.set_profiled(false); CordRep::Ref(tree()); + clear_cordz_info(); } } @@ -509,12 +511,6 @@ void Cord::InlineRep::ClearSlow() { // -------------------------------------------------------------------- // Constructors and destructors -Cord::Cord(const Cord& src) : contents_(src.contents_) { - if (CordRep* tree = contents_.tree()) { - CordRep::Ref(tree); - } -} - Cord::Cord(absl::string_view src) { const size_t n = src.size(); if (n <= InlineRep::kMaxInline) { diff --git a/absl/strings/cord.h b/absl/strings/cord.h index aefb5e53..320226d2 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -755,6 +755,23 @@ class Cord { bool is_tree() const { return data_.is_tree(); } + // Returns true if the Cord is being profiled by cordz. + bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); } + + // Returns the profiled CordzInfo, or nullptr if not sampled. + absl::cord_internal::CordzInfo* cordz_info() const { + return data_.cordz_info(); + } + + // Sets the profiled CordzInfo. `cordz_info` must not be null. + void set_cordz_info(cord_internal::CordzInfo* cordz_info) { + assert(cordz_info != nullptr); + data_.set_cordz_info(cordz_info); + } + + // Resets the current cordz_info to null / empty. + void clear_cordz_info() { data_.clear_cordz_info(); } + private: friend class Cord; @@ -921,8 +938,12 @@ Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data) : data_(data) {} -inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) { - data_ = src.data_; +inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) + : data_(src.data_) { + if (is_tree()) { + data_.clear_cordz_info(); + absl::cord_internal::CordRep::Ref(as_tree()); + } } inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) { @@ -956,7 +977,6 @@ inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { if (rhs == this) { return; } - std::swap(data_, rhs->data_); } @@ -1037,6 +1057,8 @@ inline Cord& Cord::operator=(const Cord& x) { return *this; } +inline Cord::Cord(const Cord& src) : contents_(src.contents_) {} + inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {} inline void Cord::swap(Cord& other) noexcept { diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index bf7a6820..f9982428 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -183,6 +183,10 @@ class CordTestPeer { } static bool IsTree(const Cord& c) { return c.contents_.is_tree(); } + + static cord_internal::CordzInfo* GetCordzInfo(const Cord& c) { + return c.contents_.cordz_info(); + } }; ABSL_NAMESPACE_END diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index cda00a44..a1ba67fe 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -387,6 +387,12 @@ class InlineData { as_tree_.cordz_info = absl::big_endian::FromHost64(info); } + // Resets the current cordz_info to null / empty. + void clear_cordz_info() { + assert(is_tree()); + as_tree_.cordz_info = kNullCordzInfo; + } + // Returns a read only pointer to the character data inside this instance. // Requires the current instance to hold inline data. const char* as_chars() const { -- cgit v1.2.3 From 998805a4c79d5d7a771f7e5a8ee3cbbbcba04f94 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 23 Feb 2021 07:46:36 -0800 Subject: Export of internal Abseil changes -- 32b444c0540e8255cc216171aba57639903edc22 by CJ Johnson : Add missing `final` to `absl::Cleanup` since it is not an interface type and should never be used as a base class. PiperOrigin-RevId: 359045692 GitOrigin-RevId: 32b444c0540e8255cc216171aba57639903edc22 Change-Id: I4f72714cd6f2e101709f31958af28b358f15646b --- absl/cleanup/cleanup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'absl/cleanup/cleanup.h') diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h index 8ebf1e9b..61b53d55 100644 --- a/absl/cleanup/cleanup.h +++ b/absl/cleanup/cleanup.h @@ -78,7 +78,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN template -class ABSL_MUST_USE_RESULT Cleanup { +class ABSL_MUST_USE_RESULT Cleanup final { static_assert(cleanup_internal::WasDeduced(), "Explicit template parameters are not supported."); -- cgit v1.2.3