The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) https://grpc.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

158 lines
4.8 KiB

#!/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 {
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/util/construct_destruct.h"
#include "src/core/lib/promise/detail/promise_like.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/util/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)