blob: c964407d77a1c8124eee0f1342ffedd1c8e8690a [file]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <list>
#include "base/logging.h"
#include "services/media/factory_service/event.h"
namespace mojo {
namespace media {
// Shared state for normal Events.
class EventImpl : public std::enable_shared_from_this<EventImpl> {
public:
EventImpl();
virtual ~EventImpl();
void When(const std::function<void()>& consequence) {
if (occurred_) {
consequence();
} else if (!cancelled_) {
consequences_.push_back(consequence);
}
}
void Occur() {
// Create a shared pointer to this so this object isn't destroyed during
// the consequence callback.
std::shared_ptr<EventImpl> self_ref = shared_from_this();
if (!occurred_ && !cancelled_) {
occurred_ = true;
while (!consequences_.empty()) {
consequences_.front()();
consequences_.pop_front();
}
}
}
void Cancel() {
if (!occurred_) {
cancelled_ = true;
consequences_.clear();
}
}
bool occurred() const { return occurred_; }
bool cancelled() const { return cancelled_; }
private:
bool occurred_ = false;
bool cancelled_ = false;
std::list<std::function<void()>> consequences_;
};
// Shared state for Events created with Event::First.
class FirstEventImpl : public EventImpl {
public:
FirstEventImpl(const std::vector<Event>& precursors);
~FirstEventImpl() override;
// Initializes this. A separate call is needed, because initialization may
// involve calling Occur, which calls shared_from_this, which requires that
// a shared pointer be created.
void Init();
private:
void Finished();
std::vector<Event> precursors_;
};
// Shared state for Events created with Event::All
class AllEventImpl : public EventImpl {
public:
AllEventImpl(const std::vector<Event>& precursors);
~AllEventImpl() override;
// Initializes this. A separate call is needed, because initialization may
// involve calling Occur, which calls shared_from_this, which requires that
// a shared pointer be created.
void Init();
private:
void Next();
std::vector<Event> precursors_;
std::function<void()> consequence_;
};
// static
Event Event::Create() {
return Event(std::make_shared<EventImpl>());
}
// static
Event Event::First(const std::vector<Event>& precursors) {
std::shared_ptr<FirstEventImpl> first =
std::make_shared<FirstEventImpl>(precursors);
first->Init();
return Event(first);
}
// static
Event Event::All(const std::vector<Event>& precursors) {
std::shared_ptr<AllEventImpl> all =
std::make_shared<AllEventImpl>(precursors);
all->Init();
return Event(all);
}
Event::Event() : impl_(nullptr) {}
Event::Event(const Event& other) : impl_(other.impl_) {}
Event::Event(const std::shared_ptr<EventImpl>& impl) : impl_(impl) {}
Event::~Event() {}
const Event& Event::When(const std::function<void()>& consequence) const {
DCHECK(impl_);
impl_->When(consequence);
return *this;
}
bool Event::occurred() const {
DCHECK(impl_);
return impl_->occurred();
}
bool Event::cancelled() const {
DCHECK(impl_);
return impl_->cancelled();
}
void Event::Occur() const {
DCHECK(impl_);
impl_->Occur();
}
void Event::Cancel() const {
if (impl_) {
impl_->Cancel();
}
}
EventImpl::EventImpl() {}
EventImpl::~EventImpl() {
if (!occurred_ && !cancelled_) {
LOG(WARNING) << "Event deleted before occuring or being cancelled";
}
}
FirstEventImpl::FirstEventImpl(const std::vector<Event>& precursors)
: precursors_(precursors) {
DCHECK(!precursors.empty());
}
void FirstEventImpl::Init() {
for (Event& precursor : precursors_) {
if (precursor.occurred()) {
Finished();
return;
}
}
std::function<void()> consequence = [this]() { Finished(); };
for (Event& precursor : precursors_) {
precursor.When(consequence);
}
}
FirstEventImpl::~FirstEventImpl() {
for (Event& precursor : precursors_) {
precursor.Cancel();
}
}
void FirstEventImpl::Finished() {
for (Event& precursor : precursors_) {
precursor.Cancel();
}
Occur();
precursors_.clear();
}
AllEventImpl::AllEventImpl(const std::vector<Event>& precursors)
: precursors_(precursors) {}
void AllEventImpl::Init() {
consequence_ = [this]() {
precursors_.pop_back();
Next();
};
Next();
}
AllEventImpl::~AllEventImpl() {
for (Event& precursor : precursors_) {
precursor.Cancel();
}
}
void AllEventImpl::Next() {
for (; !precursors_.empty(); precursors_.pop_back()) {
if (!precursors_.back().occurred()) {
precursors_.back().When(consequence_);
return;
}
}
Occur();
}
} // namespace media
} // namespace mojo