#ifndef STAR_PROMISE_HPP #define STAR_PROMISE_HPP #include "StarAtomicSharedPtr.hpp" namespace Star { STAR_EXCEPTION(PromiseException, StarException); // Wraps a ThreadInvoker, and can hold the value for consumption by more than // one thread, and is sharable. The return value is not taken on get(), and // access to the value via get() by multiple threads is safe. template class Promise { public: Promise(); Promise(ThreadInvoker invoker); Promise(Result result); bool valid() const; operator bool() const; bool fulfilled() const; Maybe maybe() const; Maybe maybe(); Result const& get() const; Result& get(); private: void checkValid(); struct Data { mutable Mutex mutex; Maybe> invoker; Maybe result; }; AtomicSharedPtr m_data; }; template Promise::Promise() {} template Promise::Promise(ThreadInvoker invoker) { m_data = make_shared(Data{{}, move(invoker), {}}); } template Promise::Promise(Result result) { m_data = make_shared(Data{{}, {}, move(result)}); } template bool Promise::valid() const { return m_data.valid(); } template Promise::operator bool() const { return (bool)m_data; } template bool Promise::fulfilled() const { if (!m_data) return false; MutexLocker locker(m_data->mutex); return m_data->result.isValid(); } template Maybe Promise::maybe() const { if (!m_data) return {}; MutexLocker locker(m_data->mutex); return *m_data->result; } template Maybe Promise::maybe() { if (!m_data) return {}; MutexLocker locker(m_data->mutex); return *m_data->result; } template Result const& Promise::get() const { checkValid(); MutexLocker locker(m_data->mutex); if (m_data->invoker) { m_data->result = m_data->invoker->finish(); m_data->invoker.reset(); } return *m_data->result; } template Result& Promise::get() { checkValid(); MutexLocker locker(m_data->mutex); if (m_data->invoker) { m_data->result = m_data->invoker->finish(); m_data->invoker.reset(); } return *m_data->result; } template void Promise::checkValid() { if (!m_data) throw PromiseException("Unset Promise was accessed"); } } #endif