#include #include #include #include #include namespace mbgl { template void invoke(const std::forward_list> &list, Args&& ...args) { for (const std::unique_ptr &callback : list) { assert(callback); if (callback->is()) { callback->get()(::std::forward(args)...); } } } BaseRequest::BaseRequest(const std::string &path_) : thread_id(uv_thread_self()), 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(thread_id == uv_thread_self()); notify(); } void BaseRequest::retryImmediately() { // no-op. override in child class. } void BaseRequest::notify() { assert(thread_id == uv_thread_self()); // 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 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> list = std::move(callbacks); callbacks.clear(); if (response) { invoke(list, *response); } else { invoke(list); } self.reset(); } Callback *BaseRequest::add(Callback &&callback, const util::ptr &request) { assert(thread_id == uv_thread_self()); assert(this == request.get()); if (response) { // We already have a response. Notify right away. if (callback.is()) { callback.get()(*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(std::unique_ptr(new Callback(std::move(callback)))); return callbacks.front().get(); } } void BaseRequest::remove(Callback *callback) { assert(thread_id == uv_thread_self()); callbacks.remove_if([=](const std::unique_ptr &cb) { return cb.get() == callback; }); if (callbacks.empty()) { self.reset(); } } }