Add a utility to capture arguments by move even in C++11 (#26923)

* Add a utility to capture arguments by move even in C++11

* add test

* Automated change: Fix sanity tests

* missing file

* Automated change: Fix sanity tests

* better test

* Automated change: Fix sanity tests

* fmt

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/26910/head^2
Craig Tiller 3 years ago committed by GitHub
parent 00c03c55ff
commit bb4311baed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      BUILD
  2. 36
      CMakeLists.txt
  3. 11
      build_autogenerated.yaml
  4. 75
      src/core/lib/gprpp/capture.h
  5. 12
      test/core/gprpp/BUILD
  6. 38
      test/core/gprpp/capture_test.cc
  7. 24
      tools/run_tests/generated/tests.json

@ -712,6 +712,14 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "capture",
external_deps = ["absl/utility"],
language = "c++",
public_hdrs = ["src/core/lib/gprpp/capture.h"],
deps = ["gpr_platform"],
)
grpc_cc_library(
name = "construct_destruct",
language = "c++",

36
CMakeLists.txt generated

@ -817,6 +817,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx byte_buffer_test)
add_dependencies(buildtests_cxx byte_stream_test)
add_dependencies(buildtests_cxx cancel_ares_query_test)
add_dependencies(buildtests_cxx capture_test)
add_dependencies(buildtests_cxx cel_authorization_engine_test)
add_dependencies(buildtests_cxx certificate_provider_registry_test)
add_dependencies(buildtests_cxx certificate_provider_store_test)
@ -9287,6 +9288,41 @@ target_link_libraries(cancel_ares_query_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(capture_test
test/core/gprpp/capture_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(capture_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(capture_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::utility
)
endif()
if(gRPC_BUILD_TESTS)

@ -4778,6 +4778,17 @@ targets:
deps:
- grpc++_test_config
- grpc++_test_util
- name: capture_test
gtest: true
build: test
language: c++
headers:
- src/core/lib/gprpp/capture.h
src:
- test/core/gprpp/capture_test.cc
deps:
- absl/utility:utility
uses_polling: false
- name: cel_authorization_engine_test
gtest: true
build: test

@ -0,0 +1,75 @@
// Copyright 2021 gRPC 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
//
// http://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 GRPC_CORE_LIB_GPRPP_CAPTURE_H
#define GRPC_CORE_LIB_GPRPP_CAPTURE_H
#include <grpc/impl/codegen/port_platform.h>
#include <tuple>
#include <utility>
#include "absl/utility/utility.h"
namespace grpc_core {
namespace detail {
template <typename F, typename... Captures>
class Capture {
public:
explicit Capture(F f, Captures... captures)
: f_(std::move(f)), captures_(std::move(captures)...) {}
template <typename... Args>
decltype(std::declval<F>()(static_cast<Captures*>(nullptr)...,
std::declval<Args>()...))
operator()(Args... args) {
auto f = &f_;
return absl::apply(
[f, &args...](Captures&... captures) {
return (*f)(&captures..., std::move(args)...);
},
captures_);
}
private:
GPR_NO_UNIQUE_ADDRESS F f_;
GPR_NO_UNIQUE_ADDRESS std::tuple<Captures...> captures_;
};
} // namespace detail
// C++11 helper - best explained by usage:
//
// BigThing big_thing;
// auto f = Capture(
// [](BigThing* c, int a, int b) { /*...*/ },
// std::move(big_thing));
//
// results in: f being a callable that takes arguments (int a, int b), and
// captures the original value of big_thing by move. Each call, a pointer to
// each captured thing is inserted into the argument list at the beginning so it
// can be manipulated.
//
// Captured values are mutable, and it's the users responsibility to ensure,
// should this callable be invoked from different threads, that proper locking
// is implemented.
template <typename F, typename... Captures>
detail::Capture<F, Captures...> Capture(F f, Captures... captures) {
return detail::Capture<F, Captures...>(std::move(f), std::move(captures)...);
}
} // namespace grpc_core
#endif // GRPC_CORE_LIB_GPRPP_CAPTURE_H

@ -271,3 +271,15 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "capture_test",
srcs = ["capture_test.cc"],
external_deps = ["gtest"],
language = "c++",
uses_polling = False,
deps = [
"//:capture",
"//test/core/util:grpc_suppressions",
],
)

@ -0,0 +1,38 @@
// Copyright 2021 gRPC 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
//
// http://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 "src/core/lib/gprpp/capture.h"
#include <gtest/gtest.h>
namespace grpc_core {
TEST(CaptureTest, Capture) {
auto f = Capture([](int* p) { EXPECT_EQ(*p, 42); }, 42);
f();
}
TEST(CaptureTest, WithArgsAndReturn) {
int captured = 1;
auto f =
Capture([captured](int* p, int arg) { return (captured + *p) * arg; }, 2);
EXPECT_EQ(f(2), 6);
EXPECT_EQ(f(3), 9);
}
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -3889,6 +3889,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "capture_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save