-- c68f1886f5e8fd90eb0c2d2e68feaf00a7cdacda by CJ Johnson <johnsoncj@google.com>: Introduce absl::Cleanup to the OSS repo PiperOrigin-RevId: 354583156 -- 17030cf388e10f7eb959e3e566326d1072ce392e by Abseil Team <absl-team@google.com>: Internal change only PiperOrigin-RevId: 354574953 -- e979d7236d4f3252e79ddda6739b67a9a326bf6d by CJ Johnson <johnsoncj@google.com>: Internal change PiperOrigin-RevId: 354545297 -- 7ea02b3783f7f49ef97d86a8f6580a19cc57df14 by Abseil Team <absl-team@google.com>: Pre-allocate memory for vectors where the size is known. PiperOrigin-RevId: 354344576 -- 9246c7cb11f1d6444f79ebe25acc69a8a9b870e0 by Matt Kulukundis <kfm@google.com>: Add support for Elbrus 2000 (e2k) Import of https://github.com/abseil/abseil-cpp/pull/889 PiperOrigin-RevId: 354344013 -- 0fc93d359cc1fb307552e917b37b7b2e7eed822f by Abseil Team <absl-team@google.com>: Integrate CordRepRing logic into cord (but do not enable it) PiperOrigin-RevId: 354312238 -- eda05622f7da71466723acb33403f783529df24b by Abseil Team <absl-team@google.com>: Protect ignore diagnostic with "__has_warning". PiperOrigin-RevId: 354112334 -- 47716c5d8fb10efa4fdd801d28bac414c6f8ec32 by Abseil Team <absl-team@google.com>: 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<int64> or an InlVec<InlVec<int64>>. 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<LargeCopyableOnly>/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<LargeCopyableMovable>/1 4.19ns +- 0% 3.95ns +- 1% -5.63% (p=0.000 n=11+12) BM_SwapElements<LargeCopyableMovableSwappable>/1 4.18ns +- 0% 3.99ns +- 0% -4.70% (p=0.000 n=9+11) BM_SwapElements<LargeCopyableMovable>/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<LargeCopyableOnly>/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<LargeCopyableMovableSwappable>/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<LargeCopyableMovableSwappable>/64 1.48ns +- 2% 1.66ns +- 1% +11.66% (p=0.000 n=12+11) BM_SwapElements<LargeCopyableMovableSwappable>/1k 1.48ns +- 1% 1.65ns +- 2% +11.32% (p=0.000 n=12+12) BM_SwapElements<LargeCopyableMovable>/512 1.48ns +- 2% 1.58ns +- 4% +6.62% (p=0.000 n=11+12) BM_SwapElements<LargeCopyableMovable>/1k 1.49ns +- 2% 1.58ns +- 3% +6.05% (p=0.000 n=12+12) BM_SwapElements<LargeCopyableMovable>/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 <absl-team@google.com>: Internal change PiperOrigin-RevId: 353737330 -- f206ae0983e58c9904ed8b8f05f9caf564a446be by Matt Kulukundis <kfm@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 353682256 GitOrigin-RevId: c68f1886f5e8fd90eb0c2d2e68feaf00a7cdacda Change-Id: I5790c1036c4f543c701d1039848fabf7ae881ad8pull/898/head
parent
af39e13305
commit
a9a4956020
22 changed files with 876 additions and 32 deletions
@ -0,0 +1,66 @@ |
||||
# 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. |
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") |
||||
load( |
||||
"//absl:copts/configure_copts.bzl", |
||||
"ABSL_DEFAULT_COPTS", |
||||
"ABSL_DEFAULT_LINKOPTS", |
||||
"ABSL_TEST_COPTS", |
||||
) |
||||
|
||||
package(default_visibility = ["//visibility:public"]) |
||||
|
||||
licenses(["notice"]) |
||||
|
||||
cc_library( |
||||
name = "cleanup_internal", |
||||
hdrs = ["internal/cleanup.h"], |
||||
copts = ABSL_DEFAULT_COPTS, |
||||
linkopts = ABSL_DEFAULT_LINKOPTS, |
||||
deps = [ |
||||
"//absl/base:base_internal", |
||||
"//absl/base:core_headers", |
||||
"//absl/utility", |
||||
], |
||||
) |
||||
|
||||
cc_library( |
||||
name = "cleanup", |
||||
hdrs = [ |
||||
"cleanup.h", |
||||
], |
||||
copts = ABSL_DEFAULT_COPTS, |
||||
linkopts = ABSL_DEFAULT_LINKOPTS, |
||||
deps = [ |
||||
":cleanup_internal", |
||||
"//absl/base:config", |
||||
"//absl/base:core_headers", |
||||
], |
||||
) |
||||
|
||||
cc_test( |
||||
name = "cleanup_test", |
||||
size = "small", |
||||
srcs = [ |
||||
"cleanup_test.cc", |
||||
], |
||||
copts = ABSL_TEST_COPTS, |
||||
deps = [ |
||||
":cleanup", |
||||
"//absl/base:config", |
||||
"//absl/utility", |
||||
"@com_google_googletest//:gtest_main", |
||||
], |
||||
) |
@ -0,0 +1,55 @@ |
||||
# 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. |
||||
|
||||
absl_cc_library( |
||||
NAME |
||||
cleanup_internal |
||||
HDRS |
||||
"internal/cleanup.h" |
||||
COPTS |
||||
${ABSL_DEFAULT_COPTS} |
||||
DEPS |
||||
absl::base_internal |
||||
absl::core_headers |
||||
absl::utility |
||||
PUBLIC |
||||
) |
||||
|
||||
absl_cc_library( |
||||
NAME |
||||
cleanup |
||||
HDRS |
||||
"cleanup.h" |
||||
COPTS |
||||
${ABSL_DEFAULT_COPTS} |
||||
DEPS |
||||
absl::cleanup_internal |
||||
absl::config |
||||
absl::core_headers |
||||
PUBLIC |
||||
) |
||||
|
||||
absl_cc_test( |
||||
NAME |
||||
cleanup_test |
||||
SRCS |
||||
"cleanup_test.cc" |
||||
COPTS |
||||
${ABSL_TEST_COPTS} |
||||
DEPS |
||||
absl::cleanup |
||||
absl::config |
||||
absl::utility |
||||
gmock_main |
||||
) |
@ -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 <utility> |
||||
|
||||
#include "absl/base/config.h" |
||||
#include "absl/base/macros.h" |
||||
#include "absl/cleanup/internal/cleanup.h" |
||||
|
||||
namespace absl { |
||||
ABSL_NAMESPACE_BEGIN |
||||
|
||||
template <typename Arg, typename Callback = void()> |
||||
class ABSL_MUST_USE_RESULT Cleanup { |
||||
static_assert(cleanup_internal::WasDeduced<Arg>(), |
||||
"Explicit template parameters are not supported."); |
||||
|
||||
static_assert(cleanup_internal::ReturnsVoid<Callback>(), |
||||
"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<Callback> storage_; |
||||
}; |
||||
|
||||
// `auto c = absl::MakeCleanup(/* callback */);`
|
||||
//
|
||||
// C++11 type deduction API for creating an instance of `absl::Cleanup`.
|
||||
template <typename... Args, typename Callback> |
||||
absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) { |
||||
static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(), |
||||
"Explicit template parameters are not supported."); |
||||
|
||||
static_assert(cleanup_internal::ReturnsVoid<Callback>(), |
||||
"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 <typename Callback> |
||||
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>; |
||||
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
||||
|
||||
ABSL_NAMESPACE_END |
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CLEANUP_CLEANUP_H_
|
@ -0,0 +1,240 @@ |
||||
// 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.
|
||||
|
||||
#include "absl/cleanup/cleanup.h" |
||||
|
||||
#include <functional> |
||||
#include <type_traits> |
||||
#include <utility> |
||||
|
||||
#include "gtest/gtest.h" |
||||
#include "absl/base/config.h" |
||||
#include "absl/utility/utility.h" |
||||
|
||||
namespace { |
||||
|
||||
using Tag = absl::cleanup_internal::Tag; |
||||
|
||||
template <typename Type1, typename Type2> |
||||
void AssertSameType() { |
||||
static_assert(std::is_same<Type1, Type2>::value, ""); |
||||
} |
||||
|
||||
struct IdentityFactory { |
||||
template <typename Callback> |
||||
static Callback AsCallback(Callback callback) { |
||||
return Callback(std::move(callback)); |
||||
} |
||||
}; |
||||
|
||||
// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to
|
||||
// represent users that make their own move-only callback types outside of
|
||||
// `std::function` and lambda literals.
|
||||
class FunctorClass { |
||||
using Callback = std::function<void()>; |
||||
|
||||
public: |
||||
explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {} |
||||
|
||||
FunctorClass(FunctorClass&& other) |
||||
: callback_(absl::exchange(other.callback_, Callback())) {} |
||||
|
||||
FunctorClass(const FunctorClass&) = delete; |
||||
|
||||
FunctorClass& operator=(const FunctorClass&) = delete; |
||||
|
||||
FunctorClass& operator=(FunctorClass&&) = delete; |
||||
|
||||
void operator()() const& = delete; |
||||
|
||||
void operator()() && { |
||||
ASSERT_TRUE(callback_); |
||||
callback_(); |
||||
callback_ = nullptr; |
||||
} |
||||
|
||||
private: |
||||
Callback callback_; |
||||
}; |
||||
|
||||
struct FunctorClassFactory { |
||||
template <typename Callback> |
||||
static FunctorClass AsCallback(Callback callback) { |
||||
return FunctorClass(std::move(callback)); |
||||
} |
||||
}; |
||||
|
||||
struct StdFunctionFactory { |
||||
template <typename Callback> |
||||
static std::function<void()> AsCallback(Callback callback) { |
||||
return std::function<void()>(std::move(callback)); |
||||
} |
||||
}; |
||||
|
||||
using CleanupTestParams = |
||||
::testing::Types<IdentityFactory, FunctorClassFactory, StdFunctionFactory>; |
||||
template <typename> |
||||
struct CleanupTest : public ::testing::Test {}; |
||||
TYPED_TEST_SUITE(CleanupTest, CleanupTestParams); |
||||
|
||||
bool function_pointer_called = false; |
||||
void FunctionPointerFunction() { function_pointer_called = true; } |
||||
|
||||
TYPED_TEST(CleanupTest, FactoryProducesCorrectType) { |
||||
{ |
||||
auto callback = TypeParam::AsCallback([] {}); |
||||
auto cleanup = absl::MakeCleanup(std::move(callback)); |
||||
|
||||
AssertSameType<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
auto cleanup = absl::MakeCleanup(&FunctionPointerFunction); |
||||
|
||||
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
auto cleanup = absl::MakeCleanup(FunctionPointerFunction); |
||||
|
||||
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(); |
||||
} |
||||
} |
||||
|
||||
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) |
||||
TYPED_TEST(CleanupTest, CTADProducesCorrectType) { |
||||
{ |
||||
auto callback = TypeParam::AsCallback([] {}); |
||||
absl::Cleanup cleanup = std::move(callback); |
||||
|
||||
AssertSameType<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
absl::Cleanup cleanup = &FunctionPointerFunction; |
||||
|
||||
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
absl::Cleanup cleanup = FunctionPointerFunction; |
||||
|
||||
AssertSameType<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(); |
||||
} |
||||
} |
||||
|
||||
TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) { |
||||
{ |
||||
auto callback = IdentityFactory::AsCallback([] {}); |
||||
auto factory_cleanup = absl::MakeCleanup(callback); |
||||
absl::Cleanup deduction_cleanup = callback; |
||||
|
||||
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
auto factory_cleanup = |
||||
absl::MakeCleanup(FunctorClassFactory::AsCallback([] {})); |
||||
absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {}); |
||||
|
||||
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
auto factory_cleanup = |
||||
absl::MakeCleanup(StdFunctionFactory::AsCallback([] {})); |
||||
absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {}); |
||||
|
||||
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
auto factory_cleanup = absl::MakeCleanup(&FunctionPointerFunction); |
||||
absl::Cleanup deduction_cleanup = &FunctionPointerFunction; |
||||
|
||||
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>(); |
||||
} |
||||
|
||||
{ |
||||
auto factory_cleanup = absl::MakeCleanup(FunctionPointerFunction); |
||||
absl::Cleanup deduction_cleanup = FunctionPointerFunction; |
||||
|
||||
AssertSameType<decltype(factory_cleanup), decltype(deduction_cleanup)>(); |
||||
} |
||||
} |
||||
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
|
||||
|
||||
TYPED_TEST(CleanupTest, BasicUsage) { |
||||
bool called = false; |
||||
|
||||
{ |
||||
EXPECT_FALSE(called); |
||||
|
||||
auto cleanup = |
||||
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); |
||||
|
||||
EXPECT_FALSE(called); |
||||
} |
||||
|
||||
EXPECT_TRUE(called); |
||||
} |
||||
|
||||
TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) { |
||||
function_pointer_called = false; |
||||
|
||||
{ |
||||
EXPECT_FALSE(function_pointer_called); |
||||
|
||||
auto cleanup = |
||||
absl::MakeCleanup(TypeParam::AsCallback(&FunctionPointerFunction)); |
||||
|
||||
EXPECT_FALSE(function_pointer_called); |
||||
} |
||||
|
||||
EXPECT_TRUE(function_pointer_called); |
||||
} |
||||
|
||||
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); |
||||
} |
||||
|
||||
EXPECT_FALSE(called); |
||||
} |
||||
|
||||
TYPED_TEST(CleanupTest, Invoke) { |
||||
bool called = false; |
||||
|
||||
{ |
||||
EXPECT_FALSE(called); |
||||
|
||||
auto cleanup = |
||||
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; })); |
||||
std::move(cleanup).Invoke(); |
||||
|
||||
EXPECT_TRUE(called); |
||||
} |
||||
|
||||
EXPECT_TRUE(called); |
||||
} |
||||
|
||||
} // namespace
|
@ -0,0 +1,77 @@ |
||||
// 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.
|
||||
|
||||
#ifndef ABSL_CLEANUP_INTERNAL_CLEANUP_H_ |
||||
#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_ |
||||
|
||||
#include <type_traits> |
||||
#include <utility> |
||||
|
||||
#include "absl/base/internal/invoke.h" |
||||
#include "absl/base/thread_annotations.h" |
||||
#include "absl/utility/utility.h" |
||||
|
||||
namespace absl { |
||||
ABSL_NAMESPACE_BEGIN |
||||
|
||||
namespace cleanup_internal { |
||||
|
||||
struct Tag {}; |
||||
|
||||
template <typename Arg, typename... Args> |
||||
constexpr bool WasDeduced() { |
||||
return (std::is_same<cleanup_internal::Tag, Arg>::value) && |
||||
(sizeof...(Args) == 0); |
||||
} |
||||
|
||||
template <typename Callback> |
||||
constexpr bool ReturnsVoid() { |
||||
return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value); |
||||
} |
||||
|
||||
template <typename Callback> |
||||
class Storage { |
||||
public: |
||||
explicit Storage(Callback callback) |
||||
: engaged_(true), callback_(std::move(callback)) {} |
||||
|
||||
Storage(Storage&& other) |
||||
: engaged_(absl::exchange(other.engaged_, false)), |
||||
callback_(std::move(other.callback_)) {} |
||||
|
||||
Storage(const Storage& other) = delete; |
||||
|
||||
Storage& operator=(Storage&& other) = delete; |
||||
|
||||
Storage& operator=(const Storage& other) = delete; |
||||
|
||||
bool IsCallbackEngaged() const { return engaged_; } |
||||
|
||||
void DisengageCallback() { engaged_ = false; } |
||||
|
||||
void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS { |
||||
std::move(callback_)(); |
||||
} |
||||
|
||||
private: |
||||
bool engaged_; |
||||
Callback callback_; |
||||
}; |
||||
|
||||
} // namespace cleanup_internal
|
||||
|
||||
ABSL_NAMESPACE_END |
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CLEANUP_INTERNAL_CLEANUP_H_
|
@ -1 +1 @@ |
||||
2020f |
||||
2021a |
||||
|
Binary file not shown.
Loading…
Reference in new issue