diff options
Diffstat (limited to 'src/mbgl/storage/base_request.cpp')
-rw-r--r-- | src/mbgl/storage/base_request.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/mbgl/storage/base_request.cpp b/src/mbgl/storage/base_request.cpp new file mode 100644 index 0000000000..510bd7bf1c --- /dev/null +++ b/src/mbgl/storage/base_request.cpp @@ -0,0 +1,87 @@ +#include <mbgl/storage/base_request.hpp> +#include <mbgl/storage/response.hpp> +#include <mbgl/storage/request.hpp> +#include <mbgl/util/std.hpp> + +#include <uv.h> + +#include <cassert> + +namespace mbgl { + +template <typename T, typename ...Args> +void invoke(const std::forward_list<std::unique_ptr<Callback>> &list, Args&& ...args) { + for (const std::unique_ptr<Callback> &callback : list) { + assert(callback); + if (callback->is<T>()) { + callback->get<T>()(::std::forward<Args>(args)...); + } + } +} + +BaseRequest::BaseRequest(const std::string &path_) : threadId(std::this_thread::get_id()), path(path_) { +} + +// A base request can only be "canceled" by destroying the object. In that case, we'll have to +// notify all cancel callbacks. +BaseRequest::~BaseRequest() { + assert(std::this_thread::get_id() == threadId); + notify(); +} + +void BaseRequest::retryImmediately() { + // no-op. override in child class. +} + +void BaseRequest::notify() { + assert(std::this_thread::get_id() == threadId); + + // The parameter exists solely so that any calls to ->remove() + // are not going to cause deallocation of this object while this call is in progress. + util::ptr<BaseRequest> retain = self; + + // Swap the lists so that it's safe for callbacks to call ->cancel() + // on the request object, which would modify the list. + const std::forward_list<std::unique_ptr<Callback>> list = std::move(callbacks); + callbacks.clear(); + + if (response) { + invoke<CompletedCallback>(list, *response); + } else { + invoke<AbortedCallback>(list); + } + + self.reset(); +} + +Callback *BaseRequest::add(Callback &&callback, const util::ptr<BaseRequest> &request) { + assert(std::this_thread::get_id() == threadId); + assert(this == request.get()); + + if (response) { + // We already have a response. Notify right away. + if (callback.is<CompletedCallback>()) { + callback.get<CompletedCallback>()(*response); + } else { + // We already know that this request was successful. The AbortedCallback will be discarded + // here since it would never be called. + } + return nullptr; + } else { + self = request; + callbacks.push_front(util::make_unique<Callback>(std::move(callback))); + return callbacks.front().get(); + } +} + +void BaseRequest::remove(Callback *callback) { + assert(std::this_thread::get_id() == threadId); + callbacks.remove_if([=](const std::unique_ptr<Callback> &cb) { + return cb.get() == callback; + }); + if (callbacks.empty()) { + self.reset(); + } +} + +} |