//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2018 ArangoDB GmbH, Cologne, Germany /// /// 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. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Simon Grätzer //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_FUTURES_PROMISE_H #define ARANGOD_FUTURES_PROMISE_H 1 #include "Futures/Exceptions.h" #include "Futures/SharedState.h" #include "Futures/Unit.h" namespace arangodb { namespace futures { template class Future; /// producer side of future-promise pair /// accesses on Promise have to be synchronized externally to /// be thread-safe template class Promise { static_assert(!std::is_same::value, "Promise instead of void"); public: /// make invalid promise static Promise makeEmpty() { return Promise(nullptr); } /// @brief Constructs a Promise with no shared state. /// After construction, valid() == true. Promise() : _state(detail::SharedState::make()), _retrieved(false) {} Promise(Promise const& o) = delete; Promise(Promise&& o) noexcept : _state(std::move(o._state)), _retrieved(o._retrieved) { o._state = nullptr; } ~Promise() { this->detach(); } Promise& operator=(Promise const&) = delete; Promise& operator=(Promise&& o) noexcept { if (this != &o) { detach(); _state = std::move(o._state); _retrieved = o._retrieved; o._retrieved = false; o._state = nullptr; } return *this; } bool valid() const noexcept { return _state != nullptr; } bool isFulfilled() const noexcept { if (_state) { return _state->hasResult(); } return true; } /// Fulfill the Promise with an exception_ptr. void setException(std::exception_ptr ep) { setTry(Try(ep)); } /// Fulfill the Promise with exception `e` *as if* by /// `setException(std::make_exception_ptr(e))`. template typename std::enable_if::value>::type setException(E const& e) { setException(std::make_exception_ptr(e)); } /// Fulfill the Promise with the specified value using perfect forwarding. /// Functionally equivalent to `setTry(Try(std::forward(value)))` template void setValue(M&& value) { static_assert(!std::is_same::value, "Use setValue() instead"); setTry(Try(std::forward(value))); } /// set void value template typename std::enable_if::value>::type setValue() { setTry(Try()); } /// Fulfill the Promise with the specified Try (value or exception). void setTry(Try&& t) { throwIfFulfilled(); getState().setResult(std::move(t)); } /// Fulfill this Promise with the result of a function that takes no /// arguments and returns something implicitly convertible to T. template void setWith(F&& func) { throwIfFulfilled(); getState().setResult(makeTryWith(std::forward(func))); } arangodb::futures::Future getFuture(); private: explicit Promise(detail::SharedState* state) : _state(state), _retrieved(false) {} // convenience method that checks if _state is set inline detail::SharedState& getState() { if (!_state) { throw FutureException(ErrorCode::NoState); } return *_state; } inline void throwIfFulfilled() const { if (isFulfilled()) { throw FutureException(ErrorCode::PromiseAlreadySatisfied); } } void detach() { if (_state) { if (!_retrieved) { _state->detachFuture(); } if (!_state->hasResult()) { auto ptr = std::make_exception_ptr(FutureException(ErrorCode::BrokenPromise)); _state->setResult(Try(std::move(ptr))); } _state->detachPromise(); _state = nullptr; } } private: detail::SharedState* _state; /// Whether the Future has been retrieved (a one-time operation) bool _retrieved; }; } // namespace futures } // namespace arangodb #endif // ARANGOD_FUTURES_PROMISE_H #include "Future.h" #include "Promise-inl.h"