[promises] Eliminate switch.h (#30317)

* [promises] Eliminate switch.h

Instead build a jump table that we can index into and call the appropriate function. Means that the dispatch mechanism can be done in C++ without a code generator, and so eliminates a bunch of fiddly code.

* fix

* ensure static initialization

* Automated change: Fix sanity tests

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/30515/head
Craig Tiller 2 years ago committed by GitHub
parent ebfb028a29
commit c866d65966
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      BUILD
  2. 16
      build_autogenerated.yaml
  3. 2
      gRPC-C++.podspec
  4. 2
      gRPC-Core.podspec
  5. 1
      grpc.gemspec
  6. 1
      package.xml
  7. 35
      src/core/lib/promise/detail/basic_seq.h
  8. 1455
      src/core/lib/promise/detail/switch.h
  9. 75
      tools/codegen/core/gen_switch.py
  10. 1
      tools/doxygen/Doxyfile.c++.internal
  11. 1
      tools/doxygen/Doxyfile.core.internal

10
BUILD

@ -1395,15 +1395,6 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "switch",
language = "c++",
public_hdrs = [
"src/core/lib/promise/detail/switch.h",
],
deps = ["gpr_platform"],
)
grpc_cc_library(
name = "basic_join",
external_deps = [
@ -1472,7 +1463,6 @@ grpc_cc_library(
"poll",
"promise_factory",
"promise_like",
"switch",
],
)

@ -866,7 +866,6 @@ libs:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/latch.h
@ -2051,7 +2050,6 @@ libs:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/latch.h
@ -3667,7 +3665,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/join.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/promise.h
@ -4081,7 +4078,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
@ -4929,7 +4925,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
@ -6138,7 +6133,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
@ -6222,7 +6216,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/for_each.h
- src/core/lib/promise/intra_activity_waiter.h
@ -7558,7 +7551,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/join.h
- src/core/lib/promise/latch.h
@ -7723,7 +7715,6 @@ targets:
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/seq.h
@ -7809,7 +7800,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
@ -7887,7 +7877,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
@ -8238,7 +8227,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/observable.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/promise.h
@ -8567,7 +8555,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/join.h
@ -9122,7 +9109,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
@ -9313,7 +9299,6 @@ targets:
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/seq.h
src:
@ -11175,7 +11160,6 @@ targets:
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/try_seq.h
src:

2
gRPC-C++.podspec generated

@ -825,7 +825,6 @@ Pod::Spec.new do |s|
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',
@ -1680,7 +1679,6 @@ Pod::Spec.new do |s|
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',

2
gRPC-Core.podspec generated

@ -1340,7 +1340,6 @@ Pod::Spec.new do |s|
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',
@ -2302,7 +2301,6 @@ Pod::Spec.new do |s|
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',

1
grpc.gemspec generated

@ -1253,7 +1253,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/promise/detail/promise_factory.h )
s.files += %w( src/core/lib/promise/detail/promise_like.h )
s.files += %w( src/core/lib/promise/detail/status.h )
s.files += %w( src/core/lib/promise/detail/switch.h )
s.files += %w( src/core/lib/promise/exec_ctx_wakeup_scheduler.h )
s.files += %w( src/core/lib/promise/intra_activity_waiter.h )
s.files += %w( src/core/lib/promise/latch.h )

1
package.xml generated

@ -1235,7 +1235,6 @@
<file baseinstalldir="/" name="src/core/lib/promise/detail/promise_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/promise_like.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/status.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/switch.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/exec_ctx_wakeup_scheduler.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/intra_activity_waiter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/latch.h" role="src" />

@ -17,6 +17,8 @@
#include <grpc/support/port_platform.h>
#include <stddef.h>
#include <array>
#include <cassert>
#include <new>
@ -30,12 +32,29 @@
#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/promise/detail/promise_factory.h"
#include "src/core/lib/promise/detail/promise_like.h"
#include "src/core/lib/promise/detail/switch.h"
#include "src/core/lib/promise/poll.h"
namespace grpc_core {
namespace promise_detail {
// Given f0, ..., fn, call function idx and return the result.
template <typename R, typename A, R (*... f)(A* arg)>
class JumpTable {
public:
JumpTable() = delete;
JumpTable(const JumpTable&) = delete;
static R Run(size_t idx, A* arg) { return fs_[idx](arg); }
private:
using Fn = R (*)(A* arg);
static const Fn fs_[sizeof...(f)];
};
template <typename R, typename A, R (*... f)(A* arg)>
const typename JumpTable<R, A, f...>::Fn
JumpTable<R, A, f...>::fs_[sizeof...(f)] = {f...};
// Helper for SeqState to evaluate some common types to all partial
// specializations.
template <template <typename> class Traits, typename FPromise, typename FNext>
@ -334,16 +353,14 @@ class BasicSeq {
// parameter unpacking can work.
template <char I>
struct RunStateStruct {
BasicSeq* s;
Poll<Result> operator()() { return s->RunState<I>(); }
static Poll<Result> Run(BasicSeq* s) { return s->RunState<I>(); }
};
// Similarly placate those compilers for
// DestructCurrentPromiseAndSubsequentFactories
template <char I>
struct DestructCurrentPromiseAndSubsequentFactoriesStruct {
BasicSeq* s;
void operator()() {
static void Run(BasicSeq* s) {
return s->DestructCurrentPromiseAndSubsequentFactories<I>();
}
};
@ -356,7 +373,8 @@ class BasicSeq {
// Duff's device like mechanic for evaluating sequences.
template <char... I>
Poll<Result> Run(absl::integer_sequence<char, I...>) {
return Switch<Poll<Result>>(state_, RunStateStruct<I>{this}...);
return JumpTable<Poll<Result>, BasicSeq, RunStateStruct<I>::Run...>::Run(
state_, this);
}
// Run the appropriate destructors for a given state.
@ -366,8 +384,9 @@ class BasicSeq {
// which can choose the correct instance at runtime to destroy everything.
template <char... I>
void RunDestruct(absl::integer_sequence<char, I...>) {
Switch<void>(
state_, DestructCurrentPromiseAndSubsequentFactoriesStruct<I>{this}...);
JumpTable<void, BasicSeq,
DestructCurrentPromiseAndSubsequentFactoriesStruct<I>::Run...>::
Run(state_, this);
}
public:

File diff suppressed because it is too large Load Diff

@ -1,75 +0,0 @@
#!/usr/bin/env python3
# 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.
import sys
# utility: print a big comment block into a set of files
def put_banner(files, banner):
for f in files:
print('/*', file=f)
for line in banner:
print(' * %s' % line, file=f)
print(' */', file=f)
print('', file=f)
with open('src/core/lib/promise/detail/switch.h', 'w') as H:
# copy-paste copyright notice from this file
with open(sys.argv[0]) as my_source:
copyright = []
for line in my_source:
if line[0] != '#':
break
for line in my_source:
if line[0] == '#':
copyright.append(line)
break
for line in my_source:
if line[0] != '#':
break
copyright.append(line)
put_banner([H], [line[2:].rstrip() for line in copyright])
put_banner([H], ["Automatically generated by %s" % sys.argv[0]])
print("#ifndef GRPC_CORE_LIB_PROMISE_DETAIL_SWITCH_H", file=H)
print("#define GRPC_CORE_LIB_PROMISE_DETAIL_SWITCH_H", file=H)
print('', file=H)
print('#include <grpc/impl/codegen/port_platform.h>', file=H)
print('', file=H)
print("#include <stdlib.h>", file=H)
print('', file=H)
print("namespace grpc_core {", file=H)
for n in range(1, 33):
print('', file=H)
print("template <typename R, %s> R Switch(char idx, %s) {" % (
", ".join("typename F%d" % i for i in range(0, n)),
", ".join("F%d f%d" % (i, i) for i in range(0, n)),
),
file=H)
print(" switch (idx) {", file=H)
for i in range(0, n):
print(" case %d: return f%d();" % (i, i), file=H)
print(" }", file=H)
print(" abort();", file=H)
print("}", file=H)
print('', file=H)
print("}", file=H)
print('', file=H)
print("#endif // GRPC_CORE_LIB_PROMISE_DETAIL_SWITCH_H", file=H)

@ -2236,7 +2236,6 @@ src/core/lib/promise/detail/basic_seq.h \
src/core/lib/promise/detail/promise_factory.h \
src/core/lib/promise/detail/promise_like.h \
src/core/lib/promise/detail/status.h \
src/core/lib/promise/detail/switch.h \
src/core/lib/promise/exec_ctx_wakeup_scheduler.h \
src/core/lib/promise/intra_activity_waiter.h \
src/core/lib/promise/latch.h \

@ -2029,7 +2029,6 @@ src/core/lib/promise/detail/basic_seq.h \
src/core/lib/promise/detail/promise_factory.h \
src/core/lib/promise/detail/promise_like.h \
src/core/lib/promise/detail/status.h \
src/core/lib/promise/detail/switch.h \
src/core/lib/promise/exec_ctx_wakeup_scheduler.h \
src/core/lib/promise/intra_activity_waiter.h \
src/core/lib/promise/latch.h \

Loading…
Cancel
Save