summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-09-15 17:26:44 +0200
committerKonstantin Käfer <mail@kkaefer.com>2014-09-24 16:14:09 +0200
commitd9fc7708a2dfb6e2506a5d10d896a813557c056d (patch)
tree50b2dba9e0a8766c88f7c276a8f71742a06a1d67 /include
parent062e911c6d570a794431023f9f0cb0b02cd85667 (diff)
downloadqtlocation-mapboxgl-d9fc7708a2dfb6e2506a5d10d896a813557c056d.tar.gz
do 304 requests and cache them in sqlite
Diffstat (limited to 'include')
-rw-r--r--include/mbgl/map/map.hpp8
-rw-r--r--include/mbgl/map/tile_data.hpp5
-rw-r--r--include/mbgl/platform/platform.hpp13
-rw-r--r--include/mbgl/platform/request.hpp41
-rw-r--r--include/mbgl/platform/response.hpp29
-rw-r--r--include/mbgl/storage/base_request.hpp46
-rw-r--r--include/mbgl/storage/file_request.hpp32
-rw-r--r--include/mbgl/storage/file_source.hpp54
-rw-r--r--include/mbgl/storage/http_request.hpp38
-rw-r--r--include/mbgl/storage/http_request_baton.hpp28
-rw-r--r--include/mbgl/storage/request.hpp39
-rw-r--r--include/mbgl/storage/resource_type.hpp18
-rw-r--r--include/mbgl/storage/response.hpp23
-rw-r--r--include/mbgl/storage/sqlite_store.hpp47
-rw-r--r--include/mbgl/text/glyph_store.hpp7
-rw-r--r--include/mbgl/util/filesource.hpp56
-rw-r--r--include/mbgl/util/interpolate.hpp2
-rw-r--r--include/mbgl/util/parsedate.h38
-rw-r--r--include/mbgl/util/queue.h92
-rw-r--r--include/mbgl/util/sqlite3.hpp74
-rw-r--r--include/mbgl/util/uv-channel.h29
-rw-r--r--include/mbgl/util/uv-messenger.h31
-rw-r--r--include/mbgl/util/uv-worker.h36
23 files changed, 642 insertions, 144 deletions
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index fba38879ed..98951a375c 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -35,11 +35,14 @@ public:
explicit Map(View &view);
~Map();
- // Start/stop the map render thread
+ // Start/stop the map render thread. the start() call is asynchronous, while the stop() call
+ // will block until the map rendering thread stopped.
void start();
void stop();
- // Runs the map event loop.
+ // Runs the map event loop. ONLY run this function when you want to get render a single frame
+ // with this map object. It will *not* spawn a separate thread and instead block until the
+ // frame is completely rendered.
void run();
// Triggers a lazy rerender: only performs a render when the map is not clean.
@@ -192,6 +195,7 @@ private:
Painter painter;
+ std::string styleURL;
std::string styleJSON = "";
std::string accessToken = "";
diff --git a/include/mbgl/map/tile_data.hpp b/include/mbgl/map/tile_data.hpp
index 9aaef84e04..900224be2d 100644
--- a/include/mbgl/map/tile_data.hpp
+++ b/include/mbgl/map/tile_data.hpp
@@ -19,8 +19,7 @@ class Map;
class Painter;
class SourceInfo;
class StyleLayer;
-
-namespace platform { class Request; }
+class Request;
class TileData : public std::enable_shared_from_this<TileData>,
private util::noncopyable {
@@ -72,7 +71,7 @@ public:
const SourceInfo &source;
protected:
- std::weak_ptr<platform::Request> req;
+ std::unique_ptr<Request> req;
std::string data;
// Contains the tile ID string for painting debug information.
diff --git a/include/mbgl/platform/platform.hpp b/include/mbgl/platform/platform.hpp
index e08cac5312..6356d81bb1 100644
--- a/include/mbgl/platform/platform.hpp
+++ b/include/mbgl/platform/platform.hpp
@@ -1,8 +1,6 @@
#ifndef MBGL_PLATFORM_PLATFORM
#define MBGL_PLATFORM_PLATFORM
-#include <mbgl/platform/response.hpp>
-
#include <mbgl/util/uv.hpp>
#include <memory>
@@ -13,23 +11,12 @@ namespace platform {
class Request;
-// Makes an HTTP request of a URL, preferrably on a background thread, and calls a function with the
-// results in the original thread (which runs the libuv loop).
-// If the loop pointer is NULL, the callback function will be called on an arbitrary thread.
-// Returns a cancellable request.
-std::shared_ptr<Request> request_http(const std::string &url,
- std::function<void(Response *)> callback,
- std::shared_ptr<uv::loop> loop = nullptr);
-
// Uppercase a string, potentially using platform-specific routines.
std::string uppercase(const std::string &string);
// Lowercase a string, potentially using platform-specific routines.
std::string lowercase(const std::string &string);
-// Cancels an HTTP request.
-void cancel_request_http(const std::shared_ptr<Request> &req);
-
// Shows an alpha image with the specified dimensions in a named window.
void show_debug_image(std::string name, const char *data, size_t width, size_t height);
diff --git a/include/mbgl/platform/request.hpp b/include/mbgl/platform/request.hpp
deleted file mode 100644
index 0cbacf645d..0000000000
--- a/include/mbgl/platform/request.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef MBGL_PLATFORM_REQUEST
-#define MBGL_PLATFORM_REQUEST
-
-#include <string>
-#include <functional>
-#include <memory>
-#include <atomic>
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/uv.hpp>
-
-namespace mbgl {
-namespace platform {
-
-struct Response;
-
-class Request : public std::enable_shared_from_this<Request>, private util::noncopyable {
-public:
- Request(const std::string &url,
- std::function<void(Response *)> callback,
- std::shared_ptr<uv::loop> loop);
- ~Request();
-
- void complete();
-
-private:
- static void complete(uv_async_t *async);
-
-public:
- const std::string url;
- std::unique_ptr<Response> res;
- std::atomic<bool> cancelled;
-
-public:
- uv_async_t *async = nullptr;
- std::shared_ptr<uv::loop> loop;
-};
-}
-}
-
-#endif
diff --git a/include/mbgl/platform/response.hpp b/include/mbgl/platform/response.hpp
deleted file mode 100644
index 345a2ee3df..0000000000
--- a/include/mbgl/platform/response.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef MBGL_PLATFORM_RESPONSE
-#define MBGL_PLATFORM_RESPONSE
-
-#include <string>
-#include <functional>
-#include <ctime>
-
-#include <mbgl/util/noncopyable.hpp>
-
-namespace mbgl {
-namespace platform {
-
-struct Response : private util::noncopyable {
- Response(std::function<void(Response *)> callback) : callback(callback) {}
- int16_t code = -1;
- std::string body;
- std::string error_message;
- std::time_t modified;
- std::time_t expires;
- std::function<void(Response *)> callback;
-
- void setCacheControl(const char *value);
- void setLastModified(const char *value);
-};
-
-}
-}
-
-#endif
diff --git a/include/mbgl/storage/base_request.hpp b/include/mbgl/storage/base_request.hpp
new file mode 100644
index 0000000000..b8ebd368e4
--- /dev/null
+++ b/include/mbgl/storage/base_request.hpp
@@ -0,0 +1,46 @@
+#ifndef MBGL_STORAGE_BASE_REQUEST
+#define MBGL_STORAGE_BASE_REQUEST
+
+#include <string>
+#include <forward_list>
+#include <memory>
+#include <functional>
+
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_async_s uv_async_t;
+
+namespace mbgl {
+
+class Response;
+class Request;
+using Callback = std::function<void(const Response &)>;
+
+
+class BaseRequest {
+private:
+ // Make noncopyable and immovable
+ BaseRequest(const BaseRequest &) = delete;
+ BaseRequest(BaseRequest &&) = delete;
+ BaseRequest& operator=(const BaseRequest &) = delete;
+ BaseRequest& operator=(BaseRequest &&) = delete;
+
+public:
+ BaseRequest();
+ virtual ~BaseRequest();
+
+ Callback *add(Callback &&callback, const std::shared_ptr<BaseRequest> &request);
+ void remove(Callback *callback);
+ void notify();
+
+public:
+ const unsigned long thread_id;
+ std::unique_ptr<Response> response;
+
+private:
+ std::shared_ptr<BaseRequest> self;
+ std::forward_list<std::unique_ptr<Callback>> callbacks;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/storage/file_request.hpp b/include/mbgl/storage/file_request.hpp
new file mode 100644
index 0000000000..156fd6dfe7
--- /dev/null
+++ b/include/mbgl/storage/file_request.hpp
@@ -0,0 +1,32 @@
+#ifndef MBGL_STORAGE_FILE_REQUEST
+#define MBGL_STORAGE_FILE_REQUEST
+
+
+#include <string>
+#include <memory>
+#include <cassert>
+
+#include <mbgl/storage/base_request.hpp>
+
+namespace mbgl {
+
+typedef struct uv_loop_s uv_loop_t;
+
+struct FileRequestBaton;
+
+class FileRequest : public BaseRequest {
+public:
+ FileRequest(const std::string &path, uv_loop_t *loop);
+ ~FileRequest();
+
+private:
+ const std::string path;
+ const unsigned long thread_id;
+ FileRequestBaton *ptr = nullptr;
+
+ friend struct FileRequestBaton;
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/storage/file_source.hpp b/include/mbgl/storage/file_source.hpp
new file mode 100644
index 0000000000..4cc95ae24e
--- /dev/null
+++ b/include/mbgl/storage/file_source.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_STORAGE_FILE_SOURCE
+#define MBGL_STORAGE_FILE_SOURCE
+
+#include <mbgl/storage/resource_type.hpp>
+#include <mbgl/storage/request.hpp>
+
+#include <string>
+#include <memory>
+#include <unordered_map>
+#include <functional>
+
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_messenger_s uv_messenger_t;
+
+namespace mbgl {
+
+class BaseRequest;
+class SQLiteStore;
+
+class FileSource {
+private:
+ FileSource(const FileSource &) = delete;
+ FileSource(FileSource &&) = delete;
+ FileSource& operator=(const FileSource &) = delete;
+ FileSource& operator=(FileSource &&) = delete;
+
+public:
+ FileSource(uv_loop_t *loop);
+ ~FileSource();
+
+public:
+ // Stores and retrieves the base path/URL for relative requests
+ void setBase(const std::string &value);
+ const std::string &getBase() const;
+
+ std::unique_ptr<Request> request(ResourceType type, const std::string &url);
+
+ void prepare(std::function<void()> fn);
+
+private:
+ const unsigned long thread_id;
+
+ // Stores a URL that is used as a base for loading resources with relative path.
+ std::string base;
+
+ std::unordered_map<std::string, std::weak_ptr<BaseRequest>> pending;
+ std::shared_ptr<SQLiteStore> store;
+ uv_loop_t *loop = nullptr;
+ uv_messenger_t *queue = nullptr;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/storage/http_request.hpp b/include/mbgl/storage/http_request.hpp
new file mode 100644
index 0000000000..30f7b3aa6d
--- /dev/null
+++ b/include/mbgl/storage/http_request.hpp
@@ -0,0 +1,38 @@
+#ifndef MBGL_STORAGE_HTTP_REQUEST
+#define MBGL_STORAGE_HTTP_REQUEST
+
+#include <mbgl/storage/resource_type.hpp>
+#include <mbgl/storage/base_request.hpp>
+
+#include <string>
+#include <memory>
+#include <cassert>
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace mbgl {
+
+struct CacheRequestBaton;
+struct HTTPRequestBaton;
+struct CacheEntry;
+class SQLiteStore;
+
+class HTTPRequest : public BaseRequest {
+public:
+ HTTPRequest(ResourceType type, const std::string &path, uv_loop_t *loop, std::shared_ptr<SQLiteStore> store);
+ ~HTTPRequest();
+
+private:
+ void loadedCacheEntry(std::unique_ptr<Response> &&response);
+
+private:
+ const unsigned long thread_id;
+ CacheRequestBaton *cache_baton = nullptr;
+ HTTPRequestBaton *http_baton = nullptr;
+ std::shared_ptr<SQLiteStore> store;
+ const ResourceType type;
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/storage/http_request_baton.hpp b/include/mbgl/storage/http_request_baton.hpp
new file mode 100644
index 0000000000..5f06a68cd1
--- /dev/null
+++ b/include/mbgl/storage/http_request_baton.hpp
@@ -0,0 +1,28 @@
+#ifndef MBGL_STORAGE_HTTP_REQUEST_BATON
+#define MBGL_STORAGE_HTTP_REQUEST_BATON
+
+#include <mbgl/storage/response.hpp>
+
+#include <string>
+
+typedef struct uv_async_s uv_async_t;
+
+namespace mbgl {
+
+class HTTPRequest;
+
+struct HTTPRequestBaton {
+ HTTPRequest *request = nullptr;
+ std::string path;
+ uv_async_t *async = nullptr;
+ std::unique_ptr<Response> response;
+ void *ptr = nullptr;
+ bool not_modified = false;
+
+ void start();
+ void cancel();
+};
+
+}
+
+#endif
diff --git a/include/mbgl/storage/request.hpp b/include/mbgl/storage/request.hpp
new file mode 100644
index 0000000000..fa27fbc781
--- /dev/null
+++ b/include/mbgl/storage/request.hpp
@@ -0,0 +1,39 @@
+#ifndef MBGL_STORAGE_REQUEST
+#define MBGL_STORAGE_REQUEST
+
+#include <mbgl/storage/response.hpp>
+
+#include <memory>
+#include <functional>
+#include <forward_list>
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace mbgl {
+
+class BaseRequest;
+using Callback = std::function<void(const Response &)>;
+
+class Request {
+private:
+ Request(const Request &) = delete;
+ Request(Request &&) = delete;
+ Request& operator=(const Request &) = delete;
+ Request& operator=(Request &&) = delete;
+
+public:
+ Request(const std::shared_ptr<BaseRequest> &base);
+ ~Request();
+
+ void onload(Callback cb);
+ void cancel();
+
+private:
+ const unsigned long thread_id;
+ std::shared_ptr<BaseRequest> base;
+ std::forward_list<Callback *> callbacks;
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/storage/resource_type.hpp b/include/mbgl/storage/resource_type.hpp
new file mode 100644
index 0000000000..b7204a9fa1
--- /dev/null
+++ b/include/mbgl/storage/resource_type.hpp
@@ -0,0 +1,18 @@
+#ifndef MBGL_STORAGE_RESOURCE_TYPE
+#define MBGL_STORAGE_RESOURCE_TYPE
+
+#include <cstdint>
+
+namespace mbgl {
+
+enum class ResourceType : uint8_t {
+ Unknown = 0,
+ Tile = 1,
+ Glyphs = 2,
+ Image = 3,
+ JSON = 4
+};
+
+}
+
+#endif
diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp
new file mode 100644
index 0000000000..4960173f9e
--- /dev/null
+++ b/include/mbgl/storage/response.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_STORAGE_RESPONSE
+#define MBGL_STORAGE_RESPONSE
+
+#include <string>
+#include <ctime>
+
+namespace mbgl {
+
+class Response {
+public:
+ long code = 0;
+ int64_t modified = 0;
+ int64_t expires = 0;
+ std::string data;
+
+ std::string message;
+
+ static int64_t parseCacheControl(const char *value);
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/storage/sqlite_store.hpp b/include/mbgl/storage/sqlite_store.hpp
new file mode 100644
index 0000000000..e03e6cf2bc
--- /dev/null
+++ b/include/mbgl/storage/sqlite_store.hpp
@@ -0,0 +1,47 @@
+#ifndef MBGL_STORAGE_SQLITE_STORE
+#define MBGL_STORAGE_SQLITE_STORE
+
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/response.hpp>
+
+#include <uv.h>
+
+#include <string>
+
+typedef struct uv_worker_s uv_worker_t;
+
+namespace mapbox {
+namespace sqlite {
+class Database;
+}
+}
+
+namespace mbgl {
+
+class SQLiteStore {
+public:
+ SQLiteStore(uv_loop_t *loop, const std::string &path);
+ ~SQLiteStore();
+
+ typedef void (*GetCallback)(std::unique_ptr<Response> &&entry, void *ptr);
+
+ void get(const std::string &path, GetCallback cb, void *ptr);
+ void put(const std::string &path, ResourceType type, const Response &entry);
+ void updateExpiration(const std::string &path, int64_t expires);
+
+private:
+ void createSchema();
+ void closeDatabase();
+ static void runGet(uv_work_t *req);
+ static void runPut(uv_work_t *req);
+ static void deliverResult(uv_work_t *req, int status);
+
+private:
+ const unsigned long thread_id;
+ std::shared_ptr<mapbox::sqlite::Database> db;
+ uv_worker_t *worker = nullptr;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/text/glyph_store.hpp b/include/mbgl/text/glyph_store.hpp
index e0c0391c73..9730967053 100644
--- a/include/mbgl/text/glyph_store.hpp
+++ b/include/mbgl/text/glyph_store.hpp
@@ -49,6 +49,13 @@ class GlyphPBF {
public:
GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, const std::shared_ptr<FileSource> &fileSource);
+private:
+ GlyphPBF(const GlyphPBF &) = delete;
+ GlyphPBF(GlyphPBF &&) = delete;
+ GlyphPBF &operator=(const GlyphPBF &) = delete;
+ GlyphPBF &operator=(GlyphPBF &&) = delete;
+
+public:
void parse(FontStack &stack);
std::shared_future<GlyphPBF &> getFuture();
diff --git a/include/mbgl/util/filesource.hpp b/include/mbgl/util/filesource.hpp
deleted file mode 100644
index ccff4b5122..0000000000
--- a/include/mbgl/util/filesource.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef MBGL_UTIL_FILESOURCE
-#define MBGL_UTIL_FILESOURCE
-
-#include <mbgl/util/uv.hpp>
-#include <mbgl/util/noncopyable.hpp>
-
-#include <string>
-#include <memory>
-#include <functional>
-
-typedef struct sqlite3 sqlite3;
-typedef struct sqlite3_stmt sqlite3_stmt;
-
-namespace mbgl {
-
-namespace platform {
-struct Response;
-}
-
-enum class ResourceType : uint8_t {
- Unknown = 0,
- Tile = 1,
- Glyphs = 2,
- Image = 3,
- JSON = 4
-};
-
-class FileSource : private util::noncopyable, public std::enable_shared_from_this<FileSource> {
-public:
- FileSource();
- ~FileSource();
-
- void setBase(const std::string &value);
- const std::string &getBase() const;
-
- void load(ResourceType type, const std::string &url, std::function<void(platform::Response *)> callback, const std::shared_ptr<uv::loop> loop = nullptr);
-
-private:
- void closeDatabase();
- void createSchema();
- bool loadFile(ResourceType type, const std::string &url, std::function<void(platform::Response *)> callback);
- void saveFile(ResourceType type, const std::string &url, platform::Response *res);
-
-private:
- // Stores a URL that is used as a base for loading resources with relative path.
- std::string base;
-
- // Stores the absolute path to the cache directory.
- const std::string cache;
-
- sqlite3 *db = nullptr;
-};
-
-}
-
-#endif
diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp
index e8c3389350..c9232db4eb 100644
--- a/include/mbgl/util/interpolate.hpp
+++ b/include/mbgl/util/interpolate.hpp
@@ -1,6 +1,8 @@
#ifndef MBGL_UTIL_INTERPOLATE
#define MBGL_UTIL_INTERPOLATE
+#include <array>
+
namespace mbgl {
namespace util {
diff --git a/include/mbgl/util/parsedate.h b/include/mbgl/util/parsedate.h
new file mode 100644
index 0000000000..6905e361d4
--- /dev/null
+++ b/include/mbgl/util/parsedate.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_PARSEDATE_H
+#define HEADER_PARSEDATE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+
+time_t parse_date(const char *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HEADER_PARSEDATE_H */
diff --git a/include/mbgl/util/queue.h b/include/mbgl/util/queue.h
new file mode 100644
index 0000000000..fe02b454ea
--- /dev/null
+++ b/include/mbgl/util/queue.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+typedef void *QUEUE[2];
+
+/* Private macros. */
+#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
+#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
+#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
+#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
+
+/* Public macros. */
+#define QUEUE_DATA(ptr, type, field) \
+ ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
+
+#define QUEUE_FOREACH(q, h) \
+ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
+
+#define QUEUE_EMPTY(q) \
+ ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
+
+#define QUEUE_HEAD(q) \
+ (QUEUE_NEXT(q))
+
+#define QUEUE_INIT(q) \
+ do { \
+ QUEUE_NEXT(q) = (q); \
+ QUEUE_PREV(q) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_ADD(h, n) \
+ do { \
+ QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
+ QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV(h) = QUEUE_PREV(n); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ } \
+ while (0)
+
+#define QUEUE_SPLIT(h, q, n) \
+ do { \
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(n) = (n); \
+ QUEUE_NEXT(n) = (q); \
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ QUEUE_PREV(q) = (n); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_HEAD(h, q) \
+ do { \
+ QUEUE_NEXT(q) = QUEUE_NEXT(h); \
+ QUEUE_PREV(q) = (h); \
+ QUEUE_NEXT_PREV(q) = (q); \
+ QUEUE_NEXT(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_TAIL(h, q) \
+ do { \
+ QUEUE_NEXT(q) = (h); \
+ QUEUE_PREV(q) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(q) = (q); \
+ QUEUE_PREV(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_REMOVE(q) \
+ do { \
+ QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
+ QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
+ } \
+ while (0)
+
+#endif /* QUEUE_H_ */
diff --git a/include/mbgl/util/sqlite3.hpp b/include/mbgl/util/sqlite3.hpp
new file mode 100644
index 0000000000..3e324f7ce1
--- /dev/null
+++ b/include/mbgl/util/sqlite3.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <string>
+#include <stdexcept>
+
+typedef struct sqlite3 sqlite3;
+typedef struct sqlite3_stmt sqlite3_stmt;
+
+namespace mapbox {
+namespace sqlite {
+
+enum OpenFlag : int {
+ ReadOnly = 0x00000001,
+ ReadWrite = 0x00000002,
+ Create = 0x00000004,
+ NoMutex = 0x00008000,
+ FullMutex = 0x00010000,
+ SharedCache = 0x00020000,
+ PrivateCache = 0x00040000,
+};
+
+struct Exception : std::runtime_error {
+ inline Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {}
+ const int code = 0;
+};
+
+class Statement;
+
+class Database {
+private:
+ Database(const Database &) = delete;
+ Database &operator=(const Database &) = delete;
+
+public:
+ Database(const std::string &filename, int flags = 0);
+ Database(Database &&);
+ ~Database();
+ Database &operator=(Database &&);
+
+ operator bool() const;
+
+ void exec(const std::string &sql);
+ Statement prepare(const char *query);
+
+private:
+ sqlite3 *db = nullptr;
+};
+
+class Statement {
+private:
+ Statement(const Statement &) = delete;
+ Statement &operator=(const Statement &) = delete;
+
+public:
+ Statement(sqlite3 *db, const char *sql);
+ Statement(Statement &&);
+ ~Statement();
+ Statement &operator=(Statement &&);
+
+ operator bool() const;
+
+ template <typename T> void bind(int offset, T value);
+ void bind(int offset, const std::string &value, bool retain = true);
+ template <typename T> T get(int offset);
+
+ bool run();
+ void reset();
+
+private:
+ sqlite3_stmt *stmt = nullptr;
+};
+
+}
+}
diff --git a/include/mbgl/util/uv-channel.h b/include/mbgl/util/uv-channel.h
new file mode 100644
index 0000000000..ea5c279f65
--- /dev/null
+++ b/include/mbgl/util/uv-channel.h
@@ -0,0 +1,29 @@
+#ifndef MBGL_UTIL_UV_CHANNEL
+#define MBGL_UTIL_UV_CHANNEL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <uv.h>
+
+// Taken from http://navaneeth.github.io/blog/2013/08/02/channels-in-libuv/
+
+typedef struct uv_chan_s uv_chan_t;
+
+struct uv_chan_s {
+ uv_mutex_t mutex;
+ uv_cond_t cond;
+ void *q[2];
+};
+
+int uv_chan_init(uv_chan_t *chan);
+void uv_chan_send(uv_chan_t *chan, void *data);
+void *uv_chan_receive(uv_chan_t *chan);
+void uv_chan_destroy(uv_chan_t *chan);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/mbgl/util/uv-messenger.h b/include/mbgl/util/uv-messenger.h
new file mode 100644
index 0000000000..b082466b60
--- /dev/null
+++ b/include/mbgl/util/uv-messenger.h
@@ -0,0 +1,31 @@
+#ifndef MBGL_UTIL_UV_MESSENGER
+#define MBGL_UTIL_UV_MESSENGER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <uv.h>
+
+typedef struct uv_messenger_s uv_messenger_t;
+typedef void (*uv_messenger_cb)(void *arg);
+typedef void (*uv_messenger_stop_cb)(uv_messenger_t *msgr);
+
+struct uv_messenger_s {
+ uv_mutex_t mutex;
+ uv_async_t async;
+ uv_messenger_cb callback;
+ void *data;
+ void *queue[2];
+};
+
+int uv_messenger_init(uv_loop_t *loop, uv_messenger_t *msgr, uv_messenger_cb callback);
+void uv_messenger_send(uv_messenger_t *msgr, void *arg);
+void uv_messenger_stop(uv_messenger_t *msgr);
+void uv_messenger_unref(uv_messenger_t *msgr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/mbgl/util/uv-worker.h b/include/mbgl/util/uv-worker.h
new file mode 100644
index 0000000000..b9eb10fb70
--- /dev/null
+++ b/include/mbgl/util/uv-worker.h
@@ -0,0 +1,36 @@
+#ifndef MBGL_UTIL_UV_WORKER
+#define MBGL_UTIL_UV_WORKER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct uv_messenger_s uv_messenger_t;
+
+#include <mbgl/util/uv-channel.h>
+
+#include <stdlib.h>
+
+typedef struct uv_worker_s uv_worker_t;
+
+struct uv_worker_s {
+ uv_thread_t thread;
+ uv_messenger_t *msgr;
+ uv_chan_t chan;
+ const char *name;
+};
+
+typedef void (*uv_worker_cb)(void *data);
+typedef void (*uv_worker_after_cb)(void *data);
+
+int uv_worker_init(uv_worker_t *worker, uv_loop_t *loop);
+int uv_worker_init_named(uv_worker_t *worker, uv_loop_t *loop, const char *name);
+void uv_worker_send(uv_worker_t *worker, void *data, uv_worker_cb work_cb,
+ uv_worker_after_cb after_work_cb);
+void uv_worker_close(uv_worker_t *worker);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif