diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp index 3c23d167a..c1b1daf23 100644 --- a/platform/default/sqlite_cache.cpp +++ b/platform/default/sqlite_cache.cpp @@ -131,10 +131,10 @@ std::unique_ptr SQLiteCache::get(const Resource &resource, Callback // Will try to load the URL from the SQLite database and call the callback when done. // Note that the callback is probably going to invoked from another thread, so the caller // must make sure that it can run in that thread. - return thread->invokeWithResult(&Impl::get, std::move(callback), resource); + return thread->invokeWithCallback(&Impl::get, callback, resource); } -std::unique_ptr SQLiteCache::Impl::get(const Resource &resource) { +void SQLiteCache::Impl::get(const Resource &resource, Callback callback) { try { // This is called in the SQLite event loop. if (!db) { @@ -167,14 +167,14 @@ std::unique_ptr SQLiteCache::Impl::get(const Resource &resource) { if (getStmt->get(5)) { // == compressed response->data = util::decompress(response->data); } - return std::move(response); + callback(std::move(response)); } else { // There is no data. - return nullptr; + callback(nullptr); } } catch (mapbox::sqlite::Exception& ex) { Log::Error(Event::Database, ex.code, ex.what()); - return nullptr; + callback(nullptr); } } diff --git a/platform/default/sqlite_cache_impl.hpp b/platform/default/sqlite_cache_impl.hpp index e01400a58..86c7c07bd 100644 --- a/platform/default/sqlite_cache_impl.hpp +++ b/platform/default/sqlite_cache_impl.hpp @@ -19,7 +19,7 @@ public: Impl(uv_loop_t*, const std::string &path = ":memory:"); ~Impl(); - std::unique_ptr get(const Resource&); + void get(const Resource&, Callback); void put(const Resource& resource, std::shared_ptr response); void refresh(const Resource& resource, int64_t expires); diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 55761eb26..f468ab33e 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -233,7 +233,9 @@ bool Source::handlePartialTile(const TileID& id, Worker&) { return true; } - util::ptr data = it->second.lock(); + // Note: this uses a raw pointer; we don't want the callback binding to have a + // shared pointer. + VectorTileData* data = static_cast(it->second.lock().get()); if (!data) { return true; } @@ -241,14 +243,12 @@ bool Source::handlePartialTile(const TileID& id, Worker&) { // The signal is only emitted if there was an actual change on the tile. The // tile can be in a "partial" state waiting for resources and get reparsed on // the arrival of new resources that were needed by another tile. - size_t bucketCount = static_cast(data.get())->countBuckets(); - auto callback = [this, data, bucketCount]() { - if (static_cast(data.get())->countBuckets() > bucketCount) { + size_t bucketCount = data->countBuckets(); + return data->reparse([this, data, bucketCount]() { + if (data->countBuckets() > bucketCount) { emitTileLoaded(false); } - }; - - return data->reparse(callback); + }); } TileData::State Source::addTile(MapData& data, diff --git a/src/mbgl/util/run_loop.hpp b/src/mbgl/util/run_loop.hpp index 14021ef42..c0a56e956 100644 --- a/src/mbgl/util/run_loop.hpp +++ b/src/mbgl/util/run_loop.hpp @@ -25,7 +25,7 @@ public: template void invoke(Fn&& fn, Args&&... args) { auto tuple = std::make_tuple(std::move(args)...); - auto task = std::make_shared>( + auto task = std::make_shared>( std::move(fn), std::move(tuple)); @@ -33,44 +33,24 @@ public: async.send(); } - // Invoke fn(args...) on this RunLoop, then invoke callback() on the current RunLoop. - template + // Invoke fn(args...) on this RunLoop, then invoke callback(results...) on the current RunLoop. + template std::unique_ptr - invokeWithResult(Fn&& fn, std::function callback, Args&&... args) { - auto tuple = std::make_tuple(std::move(args)...); - auto task = std::make_shared>( + invokeWithCallback(Fn&& fn, Cb&& callback, Args&&... args) { + auto flag = std::make_shared(); + *flag = false; + + auto after = RunLoop::current.get()->bind([flag, callback] (auto&&... results) { + if (!*flag) { + callback(std::move(results)...); + } + }); + + auto tuple = std::make_tuple(std::move(args)..., after); + auto task = std::make_shared>( std::move(fn), - std::move(tuple)); - - // `task` is a shared pointer with ownership in the following three places: - // 1. In the `queue` of pending invocations. - // 2. In the `WorkRequest` result. - // 3. In the lambda binding of the callback to be executed on the invoking - // RunLoop. This last shared ownership is necessary in the case where - // callback execution has been scheduled (queued on the invoking RunLoop), - // but the other two places have released ownership -- i.e. the task was - // cancelled after the work is completed, but before the callback is - // executed. In this case, the lambda binding checks the cancellation flag - // and does not execute the original callback. - - task->bind(callback); - - withMutex([&] { queue.push(task); }); - async.send(); - - return std::make_unique(task); - } - - // Invoke fn(args...) on this RunLoop, then invoke callback(result) on the current RunLoop. - template - std::unique_ptr - invokeWithResult(Fn&& fn, std::function callback, Args&&... args) { - auto tuple = std::make_tuple(std::move(args)...); - auto task = std::make_shared>( - std::move(fn), - std::move(tuple)); - - task->bind(callback); + std::move(tuple), + flag); withMutex([&] { queue.push(task); }); async.send(); @@ -79,10 +59,11 @@ public: } // Return a function that invokes the given function on this RunLoop. - template - auto bind(std::function fn) { - return [this, fn = std::move(fn)] (Args&&... args) { - invoke(std::move(fn), std::move(args)...); + template + auto bind(Fn&& fn) { + return [this, fn = std::move(fn)] (auto&&... args) { + // `this->` is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636 + this->invoke(std::move(fn), std::move(args)...); }; } @@ -91,111 +72,47 @@ public: static uv::tls current; private: - template - class Invoker : public WorkTask, public std::enable_shared_from_this> { + template + class Invoker : public WorkTask { public: - Invoker(F&& f, P&& p) - : func(std::move(f)), + Invoker(F&& f, P&& p, std::shared_ptr canceled_ = nullptr) + : canceled(canceled_), + func(std::move(f)), params(std::move(p)) { } - using C = std::function; - - void bind(C after) { - auto task = this->shared_from_this(); - callback = RunLoop::current.get()->bind(C([task, after] { - if (!task->canceled) { - after(); - } - })); - } - void operator()() override { - // We are only running the task when there's an after callback to call. This means that an - // empty after callback will be treated as a cancelled request. The mutex will be locked while - // processing so that the cancel() callback will block. + // Lock the mutex while processing so that cancel() will block. std::lock_guard lock(mutex); - if (!canceled) { - invoke(std::index_sequence_for{}); + if (!canceled || !*canceled) { + invoke(std::make_index_sequence::value>{}); } } + // If the task has not yet begun, this will cancel it. + // If the task is in progress, this will block until it completed. (Currently + // necessary because of shared state, but should be removed.) It will also + // cancel the after callback. + // If the task has completed, but the after callback has not executed, this + // will cancel the after callback. + // If the task has completed and the after callback has executed, this will + // do nothing. void cancel() override { - // Remove the after callback to indicate that this callback has been canceled. The mutex will - // block when the task is currently in progres. When the task has not begun yet, the runTask() - // method will not do anything. When the task has been completed already, and the after callback - // was run as well, this will also do nothing. std::lock_guard lock(mutex); - canceled = true; + *canceled = true; } private: template void invoke(std::index_sequence) { - func(std::forward(std::get(params))...); - if (callback) { - callback(); - } + func(std::get(std::forward

(params))...); } std::mutex mutex; - bool canceled = false; + std::shared_ptr canceled; F func; P params; - C callback; - }; - - template - class InvokerWithResult : public WorkTask, public std::enable_shared_from_this> { - public: - InvokerWithResult(F&& f, P&& p) - : func(std::move(f)), - params(std::move(p)) { - } - - using C = std::function; - - void bind(C after) { - auto task = this->shared_from_this(); - callback = RunLoop::current.get()->bind(C([task, after] (R result) { - if (!task->canceled) { - after(std::move(result)); - } - })); - } - - void operator()() override { - // We are only running the task when there's an after callback to call. This means that an - // empty after callback will be treated as a cancelled request. The mutex will be locked while - // processing so that the cancel() callback will block. - std::lock_guard lock(mutex); - if (!canceled) { - invoke(std::index_sequence_for{}); - } - } - - void cancel() override { - // Remove the after callback to indicate that this callback has been canceled. The mutex will - // block when the task is currently in progres. When the task has not begun yet, the runTask() - // method will not do anything. When the task has been completed already, and the after callback - // was run as well, this will also do nothing. - std::lock_guard lock(mutex); - canceled = true; - } - - private: - template - void invoke(std::index_sequence) { - callback(func(std::forward(std::get(params))...)); - } - - std::mutex mutex; - bool canceled = false; - - F func; - P params; - C callback; }; using Queue = std::queue>; diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp index 16bb81db1..88a709cfa 100644 --- a/src/mbgl/util/thread.hpp +++ b/src/mbgl/util/thread.hpp @@ -32,21 +32,14 @@ public: // Invoke object->fn(args...) in the runloop thread. template void invoke(Fn fn, Args&&... args) { - loop->invoke(bind(fn), std::forward(args)...); + loop->invoke(bind(fn), std::forward(args)...); } // Invoke object->fn(args...) in the runloop thread, then invoke callback(result) in the current thread. - template + template std::unique_ptr - invokeWithResult(Fn fn, std::function callback, Args&&... args) { - return loop->invokeWithResult(bind(fn), callback, std::forward(args)...); - } - - // Invoke object->fn(args...) in the runloop thread, then invoke callback(result) in the current thread. - template - std::unique_ptr - invokeWithResult(Fn fn, std::function callback, Args&&... args) { - return loop->invokeWithResult(bind(fn), callback, std::forward(args)...); + invokeWithCallback(Fn fn, Cb&& callback, Args&&... args) { + return loop->invokeWithCallback(bind(fn), callback, std::forward(args)...); } // Invoke object->fn(args...) in the runloop thread, and wait for the result. @@ -73,9 +66,11 @@ private: Thread& operator=(const Thread&) = delete; Thread& operator=(Thread&&) = delete; - template + template auto bind(Fn fn) { - return [fn, this] (Args&&... a) { return (object->*fn)(std::forward(a)...); }; + return [fn, this] (auto &&... args) { + return (object->*fn)(std::forward(args)...); + }; } template diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp index 0d83bc49f..cc9fa1566 100644 --- a/src/mbgl/util/worker.cpp +++ b/src/mbgl/util/worker.cpp @@ -20,25 +20,30 @@ public: util::ThreadContext::setFileSource(fs); } - bool parseRasterTile(RasterBucket* bucket, std::string data) { - return bucket->setImage(data); + void parseRasterTile(RasterBucket* bucket, std::string data, std::function callback) { + callback(bucket->setImage(data)); } - TileParseResult parseVectorTile(TileWorker* worker, std::string data) { + void parseVectorTile(TileWorker* worker, std::string data, std::function callback) { try { pbf tilePBF(reinterpret_cast(data.data()), data.size()); - return worker->parse(VectorTile(tilePBF)); + callback(worker->parse(VectorTile(tilePBF))); } catch (const std::exception& ex) { - return TileParseResult(ex.what()); + callback(TileParseResult(ex.what())); } } - TileParseResult parseLiveTile(TileWorker* worker, const LiveTile* tile) { - return worker->parse(*tile); + void parseLiveTile(TileWorker* worker, const LiveTile* tile, std::function callback) { + try { + callback(worker->parse(*tile)); + } catch (const std::exception& ex) { + callback(TileParseResult(ex.what())); + } } - void redoPlacement(TileWorker* worker, float angle, bool collisionDebug) { + void redoPlacement(TileWorker* worker, float angle, bool collisionDebug, std::function callback) { worker->redoPlacement(angle, collisionDebug); + callback(); } }; @@ -53,22 +58,22 @@ Worker::~Worker() = default; std::unique_ptr Worker::parseRasterTile(RasterBucket& bucket, std::string data, std::function callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithResult(&Worker::Impl::parseRasterTile, callback, &bucket, data); + return threads[current]->invokeWithCallback(&Worker::Impl::parseRasterTile, callback, &bucket, data); } std::unique_ptr Worker::parseVectorTile(TileWorker& worker, std::string data, std::function callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithResult(&Worker::Impl::parseVectorTile, callback, &worker, data); + return threads[current]->invokeWithCallback(&Worker::Impl::parseVectorTile, callback, &worker, data); } std::unique_ptr Worker::parseLiveTile(TileWorker& worker, const LiveTile& tile, std::function callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithResult(&Worker::Impl::parseLiveTile, callback, &worker, &tile); + return threads[current]->invokeWithCallback(&Worker::Impl::parseLiveTile, callback, &worker, &tile); } std::unique_ptr Worker::redoPlacement(TileWorker& worker, float angle, bool collisionDebug, std::function callback) { current = (current + 1) % threads.size(); - return threads[current]->invokeWithResult(&Worker::Impl::redoPlacement, callback, &worker, angle, collisionDebug); + return threads[current]->invokeWithCallback(&Worker::Impl::redoPlacement, callback, &worker, angle, collisionDebug); } } // end namespace mbgl diff --git a/test/miscellaneous/thread.cpp b/test/miscellaneous/thread.cpp index 68f8ddccd..78e6ffee6 100644 --- a/test/miscellaneous/thread.cpp +++ b/test/miscellaneous/thread.cpp @@ -17,9 +17,9 @@ public: EXPECT_EQ(val, 1); } - int fn2() { + void fn2(std::function cb) { EXPECT_EQ(tid, std::this_thread::get_id()); - return 1; + cb(1); } void transferIn(std::unique_ptr val) { @@ -27,15 +27,15 @@ public: EXPECT_EQ(*val, 1); } - std::unique_ptr transferOut() { + void transferOut(std::function)> cb) { EXPECT_EQ(tid, std::this_thread::get_id()); - return std::make_unique(1); + cb(std::make_unique(1)); } - std::unique_ptr transferInOut(std::unique_ptr val) { + void transferInOut(std::unique_ptr val, std::function)> cb) { EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(*val, 1); - return std::move(val); + cb(std::move(val)); } void transferInShared(std::shared_ptr val) { @@ -43,21 +43,21 @@ public: EXPECT_EQ(*val, 1); } - std::shared_ptr transferOutShared() { + void transferOutShared(std::function)> cb) { EXPECT_EQ(tid, std::this_thread::get_id()); - return std::make_shared(1); + cb(std::make_shared(1)); } - std::string transferString(const std::string& string) { + void transferString(const std::string& string, std::function cb) { EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(string, "test"); - return string; + cb(string); } - bool checkContext() const { - return ThreadContext::currentlyOn(ThreadType::Worker) + void checkContext(std::function cb) const { + cb(ThreadContext::currentlyOn(ThreadType::Worker) && ThreadContext::getName() == "Test" - && ThreadContext::getPriority() == ThreadPriority::Low; + && ThreadContext::getPriority() == ThreadPriority::Low); } const std::thread::id tid; @@ -74,35 +74,35 @@ TEST(Thread, invoke) { Thread thread({"Test", ThreadType::Map, ThreadPriority::Regular}, tid); thread.invoke(&TestObject::fn1, 1); - requests.push_back(thread.invokeWithResult(&TestObject::fn2, [&] (int result) { + requests.push_back(thread.invokeWithCallback(&TestObject::fn2, [&] (int result) { EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(result, 1); })); thread.invoke(&TestObject::transferIn, std::make_unique(1)); - requests.push_back(thread.invokeWithResult>(&TestObject::transferOut, [&] (std::unique_ptr result) { + requests.push_back(thread.invokeWithCallback(&TestObject::transferOut, [&] (std::unique_ptr result) { EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(*result, 1); })); - requests.push_back(thread.invokeWithResult>(&TestObject::transferInOut, [&] (std::unique_ptr result) { + requests.push_back(thread.invokeWithCallback(&TestObject::transferInOut, [&] (std::unique_ptr result) { EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(*result, 1); }, std::make_unique(1))); thread.invoke(&TestObject::transferInShared, std::make_shared(1)); - requests.push_back(thread.invokeWithResult>(&TestObject::transferOutShared, [&] (std::shared_ptr result) { + requests.push_back(thread.invokeWithCallback(&TestObject::transferOutShared, [&] (std::shared_ptr result) { EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(*result, 1); })); // Cancelled request - thread.invokeWithResult(&TestObject::fn1, [&] { + thread.invokeWithCallback(&TestObject::fn2, [&] (int) { ADD_FAILURE(); - }, 1); + }); std::string test("test"); - requests.push_back(thread.invokeWithResult(&TestObject::transferString, [&] (std::string result){ + requests.push_back(thread.invokeWithCallback(&TestObject::transferString, [&] (std::string result){ EXPECT_EQ(tid, std::this_thread::get_id()); EXPECT_EQ(result, "test"); loop.stop(); @@ -128,7 +128,7 @@ TEST(Thread, context) { loop.invoke([&] { Thread thread({"Test", ThreadType::Worker, ThreadPriority::Low}, tid); - requests.push_back(thread.invokeWithResult(&TestObject::checkContext, [&] (bool inTestThreadContext) { + requests.push_back(thread.invokeWithCallback(&TestObject::checkContext, [&] (bool inTestThreadContext) { EXPECT_EQ(inTestThreadContext, true); loop.stop(); })); @@ -139,8 +139,13 @@ TEST(Thread, context) { class TestWorker { public: - TestWorker(uv_loop_t*) {} - void send(std::function fn) { fn(); } + TestWorker(uv_loop_t*) { + } + + void send(std::function fn, std::function cb) { + fn(); + cb(); + } }; TEST(Thread, ExecutesAfter) { @@ -150,7 +155,7 @@ TEST(Thread, ExecutesAfter) { bool didWork = false; bool didAfter = false; - auto request = thread.invokeWithResult(&TestWorker::send, [&] { + auto request = thread.invokeWithCallback(&TestWorker::send, [&] { didAfter = true; loop.stop(); }, [&] { @@ -170,7 +175,7 @@ TEST(Thread, WorkRequestDeletionWaitsForWorkToComplete) { std::promise started; bool didWork = false; - auto request = thread.invokeWithResult(&TestWorker::send, [&] {}, [&] { + auto request = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] { started.set_value(); usleep(10000); didWork = true; @@ -188,7 +193,7 @@ TEST(Thread, WorkRequestDeletionCancelsAfter) { std::promise started; bool didAfter = false; - auto request = thread.invokeWithResult(&TestWorker::send, [&] { + auto request = thread.invokeWithCallback(&TestWorker::send, [&] { didAfter = true; }, [&] { started.set_value(); @@ -206,12 +211,12 @@ TEST(Thread, WorkRequestDeletionCancelsImmediately) { std::promise started; - auto request1 = thread.invokeWithResult(&TestWorker::send, [&] {}, [&] { + auto request1 = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] { usleep(10000); started.set_value(); }); - auto request2 = thread.invokeWithResult(&TestWorker::send, [&] {}, [&] { + auto request2 = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] { ADD_FAILURE() << "Second work item should not be invoked"; }); request2.reset(); diff --git a/test/storage/database.cpp b/test/storage/database.cpp index b54b69a13..a7560262f 100644 --- a/test/storage/database.cpp +++ b/test/storage/database.cpp @@ -15,8 +15,9 @@ TEST_F(Storage, DatabaseDoesNotExist) { SQLiteCache::Impl cache(nullptr, "test/fixtures/404/cache.db"); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_EQ(nullptr, res.get()); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_EQ(nullptr, res.get()); + }); auto observer = Log::removeObserver(); EXPECT_EQ(1ul, dynamic_cast(observer.get())->count({ EventSeverity::Error, Event::Database, 14, "unable to open database file" })); @@ -56,8 +57,9 @@ TEST_F(Storage, DatabaseCreate) { SQLiteCache::Impl cache(nullptr, "test/fixtures/database/cache.db"); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_EQ(nullptr, res.get()); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_EQ(nullptr, res.get()); + }); Log::removeObserver(); } @@ -115,8 +117,9 @@ TEST_F(Storage, DatabaseLockedRead) { // First request should fail. Log::setObserver(std::make_unique()); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_EQ(nullptr, res.get()); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_EQ(nullptr, res.get()); + }); // Make sure that we got a few "database locked" errors auto observer = Log::removeObserver(); @@ -131,8 +134,9 @@ TEST_F(Storage, DatabaseLockedRead) { // First, try getting a file (the cache value should not exist). Log::setObserver(std::make_unique()); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_EQ(nullptr, res.get()); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_EQ(nullptr, res.get()); + }); // Make sure that we got a no errors Log::removeObserver(); @@ -157,8 +161,9 @@ TEST_F(Storage, DatabaseLockedWrite) { auto response = std::make_shared(); cache.put({ Resource::Unknown, "mapbox://test" }, response); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_EQ(nullptr, res.get()); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_EQ(nullptr, res.get()); + }); auto observer = Log::removeObserver(); auto flo = dynamic_cast(observer.get()); @@ -175,9 +180,10 @@ TEST_F(Storage, DatabaseLockedWrite) { auto response = std::make_shared(); response->data = "Demo"; cache.put({ Resource::Unknown, "mapbox://test" }, response); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_NE(nullptr, res.get()); - EXPECT_EQ("Demo", res->data); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_NE(nullptr, res.get()); + EXPECT_EQ("Demo", res->data); + }); // Make sure that we got a no errors Log::removeObserver(); @@ -206,8 +212,9 @@ TEST_F(Storage, DatabaseLockedRefresh) { auto response = std::make_shared(); response->data = "Demo"; cache.put({ Resource::Unknown, "mapbox://test" }, response); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_EQ(nullptr, res.get()); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_EQ(nullptr, res.get()); + }); auto observer = Log::removeObserver(); auto flo = dynamic_cast(observer.get()); @@ -221,8 +228,9 @@ TEST_F(Storage, DatabaseLockedRefresh) { auto response = std::make_shared(); response->data = "Demo"; cache.refresh({ Resource::Unknown, "mapbox://test" }, response->expires); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_EQ(nullptr, res.get()); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_EQ(nullptr, res.get()); + }); // Make sure that we got the right errors. auto observer = Log::removeObserver(); @@ -249,9 +257,10 @@ TEST_F(Storage, DatabaseDeleted) { auto response = std::make_shared(); response->data = "Demo"; cache.put({ Resource::Unknown, "mapbox://test" }, response); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_NE(nullptr, res.get()); - EXPECT_EQ("Demo", res->data); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_NE(nullptr, res.get()); + EXPECT_EQ("Demo", res->data); + }); Log::removeObserver(); } @@ -265,9 +274,10 @@ TEST_F(Storage, DatabaseDeleted) { auto response = std::make_shared(); response->data = "Demo"; cache.put({ Resource::Unknown, "mapbox://test" }, response); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_NE(nullptr, res.get()); - EXPECT_EQ("Demo", res->data); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_NE(nullptr, res.get()); + EXPECT_EQ("Demo", res->data); + }); auto observer = Log::removeObserver(); auto flo = dynamic_cast(observer.get()); @@ -294,9 +304,10 @@ TEST_F(Storage, DatabaseInvalid) { auto response = std::make_shared(); response->data = "Demo"; cache.put({ Resource::Unknown, "mapbox://test" }, response); - std::unique_ptr res = cache.get({ Resource::Unknown, "mapbox://test" }); - EXPECT_NE(nullptr, res.get()); - EXPECT_EQ("Demo", res->data); + cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr res) { + EXPECT_NE(nullptr, res.get()); + EXPECT_EQ("Demo", res->data); + }); auto observer = Log::removeObserver(); auto flo = dynamic_cast(observer.get());