Commit a0d2309a authored by Lewis Baker's avatar Lewis Baker Committed by Facebook Github Bot

Add folly::coro::AsyncGenerator<T>

Summary:
The AsyncGenerator<T> class allows you to write a coroutine that asynchronously produces a sequence of values of type T.

This has the same executor-affinity behaviour for co_await as for Task<T> except that the executor can change at co_yield points to inherit the executor from the consumer each time a new value is requested.

Reviewed By: ericniebler

Differential Revision: D14446089

fbshipit-source-id: 710ad922918a135e1fe6eef853410c9a77cc2c28
parent 49a8f35d
This diff is collapsed.
......@@ -27,8 +27,13 @@ struct co_current_executor_ {
using co_current_executor_t = detail::co_current_executor_;
// A special singleton object that can be co_await'ed within a Task<T> to query
// the current executor associated with the Task.
// Special placeholder object that can be 'co_await'ed from within a Task<T>
// or an AsyncGenerator<T> to obtain the current folly::Executor associated
// with the current coroutine.
//
// Note that for a folly::Task the executor will remain the same throughout
// the lifetime of the coroutine. For a folly::AsyncGenerator<T> the current
// executor may change when resuming from a co_yield suspend-point.
//
// Example:
// folly::coro::Task<void> example() {
......
/*
* Copyright 2018-present Facebook, Inc.
*
* 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.
*/
#pragma once
#include <memory>
#include <type_traits>
namespace folly {
namespace coro {
namespace detail {
// Helper class for a variable with manually-controlled lifetime.
//
// You must explicitly call .construct() to construct/initialise the value.
//
// If it has been initialised then you must explicitly call .destruct() before
// the ManualLifetime object is destroyed to ensure the destructor is run.
template <typename T>
class ManualLifetime {
public:
ManualLifetime() noexcept {}
~ManualLifetime() {}
template <
typename... Args,
std::enable_if_t<std::is_constructible_v<T, Args...>, int> = 0>
void construct(Args&&... args) noexcept(
noexcept(std::is_nothrow_constructible_v<T, Args...>)) {
new (static_cast<void*>(std::addressof(value_)))
T(static_cast<Args&&>(args)...);
}
void destruct() noexcept {
value_.~T();
}
const T& get() const& {
return value_;
}
T& get() & {
return value_;
}
const T&& get() const&& {
return static_cast<const T&&>(value_);
}
T&& get() && {
return static_cast<T&&>(value_);
}
private:
union {
std::remove_const_t<T> value_;
};
};
template <typename T>
class ManualLifetime<T&> {
public:
ManualLifetime() noexcept : ptr_(nullptr) {}
~ManualLifetime() {}
void construct(T& value) noexcept {
ptr_ = std::addressof(value);
}
void destruct() noexcept {
ptr_ = nullptr;
}
T& get() const noexcept {
return *ptr_;
}
private:
T* ptr_;
};
template <typename T>
class ManualLifetime<T&&> {
public:
ManualLifetime() noexcept : ptr_(nullptr) {}
~ManualLifetime() {}
void construct(T&& value) noexcept {
ptr_ = std::addressof(value);
}
void destruct() noexcept {
ptr_ = nullptr;
}
T&& get() const noexcept {
return static_cast<T&&>(*ptr_);
}
private:
T* ptr_;
};
} // namespace detail
} // namespace coro
} // namespace folly
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment