/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see .
Copyright 2017-2019 Telegram Systems LLP
*/
#include "td/actor/MultiPromise.h"
#include
namespace td {
namespace detail {
class MultiPromiseImpl {
public:
explicit MultiPromiseImpl(MultiPromise::Options options) : options_(options) {
}
~MultiPromiseImpl() {
for (auto &promise : pending_) {
promise.set_value(Unit());
}
}
void on_status(Status status) {
if (status.is_ok() || options_.ignore_errors) {
return;
}
std::vector> promises;
{
std::unique_lock lock(mutex_);
if (pending_error_.is_ok()) {
pending_error_ = status.clone();
std::swap(promises, pending_);
} else {
CHECK(pending_.empty());
}
}
for (auto &promise : promises) {
promise.set_error(status.clone());
}
}
void add_promise(Promise<> promise) {
if (options_.ignore_errors) {
pending_.push_back(std::move(promise));
}
Status status;
{
std::unique_lock lock(mutex_);
if (pending_error_.is_error()) {
status = pending_error_.clone();
} else {
pending_.push_back(std::move(promise));
}
}
if (status.is_error()) {
promise.set_error(std::move(status));
}
}
private:
std::mutex mutex_;
std::vector> pending_;
MultiPromise::Options options_;
Status pending_error_;
};
} // namespace detail
void MultiPromise::InitGuard::add_promise(Promise<> promise) {
impl_->add_promise(std::move(promise));
}
Promise<> MultiPromise::InitGuard::get_promise() {
return [impl = impl_](Result result) {
if (result.is_ok()) {
impl->on_status(Status::OK());
} else {
impl->on_status(result.move_as_error());
}
};
}
bool MultiPromise::InitGuard::empty() const {
return !impl_;
}
MultiPromise::InitGuard::operator bool() const {
return !empty();
}
MultiPromise::InitGuard MultiPromise::init_guard() {
CHECK(!impl_.lock());
auto impl = std::make_shared(options_);
impl_ = impl;
return InitGuard(std::move(impl));
}
MultiPromise::InitGuard MultiPromise::add_promise_or_init(Promise<> promise) {
auto impl = impl_.lock();
if (!impl) {
auto guard = init_guard();
guard.add_promise(std::move(promise));
return guard;
}
impl->add_promise(std::move(promise));
return {};
}
} // namespace td