|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
# Copyright 2023 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
|
|
|
|
|
|
|
|
from mako.template import Template
|
|
|
|
|
|
|
|
join_state = Template(
|
|
|
|
"""
|
|
|
|
template <class Traits, ${",".join(f"typename P{i}" for i in range(0,n))}>
|
|
|
|
struct JoinState<Traits, ${",".join(f"P{i}" for i in range(0,n))}> {
|
|
|
|
template <typename T>
|
|
|
|
using UnwrappedType = decltype(Traits::Unwrapped(std::declval<T>()));
|
|
|
|
% for i in range(0,n):
|
|
|
|
using Promise${i} = PromiseLike<P${i}>;
|
|
|
|
using Result${i} = UnwrappedType<typename Promise${i}::Result>;
|
|
|
|
union {
|
|
|
|
GPR_NO_UNIQUE_ADDRESS Promise${i} promise${i};
|
|
|
|
GPR_NO_UNIQUE_ADDRESS Result${i} result${i};
|
|
|
|
};
|
|
|
|
% endfor
|
|
|
|
GPR_NO_UNIQUE_ADDRESS BitSet<${n}> ready;
|
|
|
|
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION JoinState(${",".join(f"P{i}&& p{i}" for i in range(0,n))}) {
|
|
|
|
% for i in range(0,n):
|
|
|
|
Construct(&promise${i}, std::forward<P${i}>(p${i}));
|
|
|
|
% endfor
|
|
|
|
}
|
|
|
|
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION JoinState(const JoinState& other) {
|
|
|
|
DCHECK(other.ready.none());
|
|
|
|
% for i in range(0,n):
|
|
|
|
Construct(&promise${i}, other.promise${i});
|
|
|
|
% endfor
|
|
|
|
}
|
|
|
|
JoinState& operator=(const JoinState& other) = delete;
|
|
|
|
JoinState& operator=(JoinState&& other) = delete;
|
|
|
|
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION JoinState(JoinState&& other) noexcept {
|
|
|
|
DCHECK(other.ready.none());
|
|
|
|
% for i in range(0,n):
|
|
|
|
Construct(&promise${i}, std::move(other.promise${i}));
|
|
|
|
% endfor
|
|
|
|
}
|
|
|
|
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION ~JoinState() {
|
|
|
|
% for i in range(0,n):
|
|
|
|
if (ready.is_set(${i})) {
|
|
|
|
Destruct(&result${i});
|
|
|
|
} else {
|
|
|
|
Destruct(&promise${i});
|
|
|
|
}
|
|
|
|
% endfor
|
|
|
|
}
|
|
|
|
using Result = typename Traits::template ResultType<std::tuple<
|
|
|
|
${",".join(f"Result{i}" for i in range(0,n))}>>;
|
|
|
|
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION Poll<Result> PollOnce() {
|
|
|
|
% for i in range(0,n):
|
|
|
|
if (!ready.is_set(${i})) {
|
|
|
|
GRPC_TRACE_VLOG(promise_primitives, 2) << "join[" << this << "]: begin poll joint ${i+1}/${n}";
|
|
|
|
auto poll = promise${i}();
|
|
|
|
GRPC_TRACE_VLOG(promise_primitives, 2) << "join[" << this << "]: end poll joint ${i+1}/${n} "
|
|
|
|
<< (poll.pending()? "pending" : (Traits::IsOk(poll.value())? "ready" : "early-error"));
|
|
|
|
if (auto* p = poll.value_if_ready()) {
|
|
|
|
if (Traits::IsOk(*p)) {
|
|
|
|
ready.set(${i});
|
|
|
|
Destruct(&promise${i});
|
|
|
|
Construct(&result${i}, Traits::Unwrapped(std::move(*p)));
|
|
|
|
} else {
|
|
|
|
return Traits::template EarlyReturn<Result>(std::move(*p));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (GRPC_TRACE_FLAG_ENABLED(promise_primitives)) {
|
|
|
|
GRPC_TRACE_VLOG(promise_primitives, 2) << "join[" << this << "]: joint ${i+1}/${n} already ready";
|
|
|
|
}
|
|
|
|
% endfor
|
|
|
|
if (ready.all()) {
|
|
|
|
return Traits::FinalReturn(${",".join(f"std::move(result{i})" for i in range(0,n))});
|
|
|
|
}
|
|
|
|
return Pending{};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
|
|
|
|
front_matter = """
|
|
|
|
#ifndef GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H
|
|
|
|
#define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H
|
|
|
|
|
|
|
|
// This file is generated by tools/codegen/core/gen_join.py
|
|
|
|
|
|
|
|
#include <grpc/support/port_platform.h>
|
|
|
|
|
|
|
|
#include "absl/log/check.h"
|
|
|
|
#include "absl/log/log.h"
|
|
|
|
|
|
|
|
#include "src/core/lib/debug/trace.h"
|
|
|
|
#include "src/core/lib/gprpp/construct_destruct.h"
|
|
|
|
#include "src/core/lib/promise/detail/promise_like.h"
|
|
|
|
#include "src/core/lib/promise/poll.h"
|
|
|
|
#include "src/core/lib/gprpp/bitset.h"
|
|
|
|
#include <tuple>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace grpc_core {
|
|
|
|
namespace promise_detail {
|
|
|
|
template <class Traits, typename... Ps>
|
|
|
|
struct JoinState;
|
|
|
|
"""
|
|
|
|
|
|
|
|
end_matter = """
|
|
|
|
} // namespace promise_detail
|
|
|
|
} // namespace grpc_core
|
|
|
|
|
|
|
|
#endif // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_JOIN_STATE_H
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
# utility: print a big comment block into a set of files
|
|
|
|
def put_banner(files, banner):
|
|
|
|
for f in files:
|
|
|
|
for line in banner:
|
|
|
|
print("// %s" % line, file=f)
|
|
|
|
print("", file=f)
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
copyright = [line[2:].rstrip() for line in copyright]
|
|
|
|
|
|
|
|
with open("src/core/lib/promise/detail/join_state.h", "w") as f:
|
|
|
|
put_banner([f], copyright)
|
|
|
|
print(front_matter, file=f)
|
|
|
|
for n in range(2, 10):
|
|
|
|
print(join_state.render(n=n), file=f)
|
|
|
|
print(end_matter, file=f)
|