summaryrefslogtreecommitdiff
path: root/include/mbgl/util
diff options
context:
space:
mode:
Diffstat (limited to 'include/mbgl/util')
-rw-r--r--include/mbgl/util/constants.hpp6
-rw-r--r--include/mbgl/util/convert.hpp6
-rw-r--r--include/mbgl/util/image.hpp49
-rw-r--r--include/mbgl/util/immutable.hpp133
-rw-r--r--include/mbgl/util/indexed_tuple.hpp7
-rw-r--r--include/mbgl/util/interpolate.hpp6
-rw-r--r--include/mbgl/util/noncopyable.hpp8
-rw-r--r--include/mbgl/util/projection.hpp22
-rw-r--r--include/mbgl/util/range.hpp6
-rw-r--r--include/mbgl/util/run_loop.hpp21
-rw-r--r--include/mbgl/util/size.hpp4
-rw-r--r--include/mbgl/util/string.hpp25
-rw-r--r--include/mbgl/util/thread.hpp161
-rw-r--r--include/mbgl/util/tileset.hpp19
-rw-r--r--include/mbgl/util/unitbezier.hpp8
-rw-r--r--include/mbgl/util/util.hpp7
-rw-r--r--include/mbgl/util/work_task.hpp3
-rw-r--r--include/mbgl/util/work_task_impl.hpp44
18 files changed, 445 insertions, 90 deletions
diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp
index dbc4bddde5..d5e55065c4 100644
--- a/include/mbgl/util/constants.hpp
+++ b/include/mbgl/util/constants.hpp
@@ -38,10 +38,13 @@ constexpr double MIN_ZOOM = 0.0;
constexpr double MAX_ZOOM = 25.5;
constexpr float MIN_ZOOM_F = MIN_ZOOM;
constexpr float MAX_ZOOM_F = MAX_ZOOM;
+constexpr uint8_t DEFAULT_MAX_ZOOM = 22;
+
+constexpr uint8_t DEFAULT_PREFETCH_ZOOM_DELTA = 4;
constexpr uint64_t DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024;
-constexpr Duration DEFAULT_FADE_DURATION = Milliseconds(300);
+constexpr Duration DEFAULT_TRANSITION_DURATION = Milliseconds(300);
constexpr Seconds CLOCK_SKEW_RETRY_TIMEOUT { 30 };
constexpr UnitBezier DEFAULT_TRANSITION_EASE = { 0, 0, 0.25, 1 };
@@ -58,7 +61,6 @@ extern const bool tileParseWarnings;
extern const bool styleParseWarnings;
extern const bool spriteWarnings;
extern const bool renderWarnings;
-extern const bool renderTree;
extern const bool labelTextMissingWarning;
extern const bool missingFontStackWarning;
extern const bool missingFontFaceWarning;
diff --git a/include/mbgl/util/convert.hpp b/include/mbgl/util/convert.hpp
index c2b3d9950d..02ec7feef9 100644
--- a/include/mbgl/util/convert.hpp
+++ b/include/mbgl/util/convert.hpp
@@ -1,3 +1,5 @@
+#include <mbgl/util/util.hpp>
+
#include <array>
#include <type_traits>
#include <utility>
@@ -7,8 +9,8 @@ namespace util {
template<typename To, typename From, std::size_t Size,
typename = std::enable_if_t<std::is_convertible<From, To>::value>>
-constexpr std::array<To, Size> convert(const std::array<From, Size>&from) {
- std::array<To, Size> to {};
+MBGL_CONSTEXPR std::array<To, Size> convert(const std::array<From, Size>&from) {
+ std::array<To, Size> to {{}};
std::copy(std::begin(from), std::end(from), std::begin(to));
return to;
}
diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp
index a41b8462bd..4887058f79 100644
--- a/include/mbgl/util/image.hpp
+++ b/include/mbgl/util/image.hpp
@@ -5,6 +5,7 @@
#include <mbgl/util/size.hpp>
#include <string>
+#include <cstring>
#include <memory>
#include <algorithm>
@@ -66,9 +67,9 @@ public:
template <typename T = Image>
T clone() const {
- T copy(size);
- std::copy(data.get(), data.get() + bytes(), copy.data.get());
- return copy;
+ T copy_(size);
+ std::copy(data.get(), data.get() + bytes(), copy_.data.get());
+ return copy_;
}
size_t stride() const { return channels * size.width; }
@@ -78,10 +79,52 @@ public:
std::fill(data.get(), data.get() + bytes(), value);
}
+ void resize(Size size_) {
+ if (size == size_) {
+ return;
+ }
+ Image newImage(size_);
+ newImage.fill(0);
+ copy(*this, newImage, {0, 0}, {0, 0}, {
+ std::min(size.width, size_.width),
+ std::min(size.height, size_.height)
+ });
+ operator=(std::move(newImage));
+ }
+
+ // Clears the rect area specified by `pt` and `size` from `dstImage`.
+ static void clear(Image& dstImg, const Point<uint32_t>& pt, const Size& size) {
+ if (size.isEmpty()) {
+ return;
+ }
+
+ if (!dstImg.valid()) {
+ throw std::invalid_argument("invalid destination for image clear");
+ }
+
+ if (size.width > dstImg.size.width ||
+ size.height > dstImg.size.height ||
+ pt.x > dstImg.size.width - size.width ||
+ pt.y > dstImg.size.height - size.height) {
+ throw std::out_of_range("out of range destination coordinates for image clear");
+ }
+
+ uint8_t* dstData = dstImg.data.get();
+
+ for (uint32_t y = 0; y < size.height; y++) {
+ const std::size_t dstOffset = (pt.y + y) * dstImg.stride() + pt.x * channels;
+ std::memset(dstData + dstOffset, 0, size.width * channels);
+ }
+ }
+
// Copy image data within `rect` from `src` to the rectangle of the same size at `pt`
// in `dst`. If the specified bounds exceed the bounds of the source or destination,
// throw `std::out_of_range`. Must not be used to move data within a single Image.
static void copy(const Image& srcImg, Image& dstImg, const Point<uint32_t>& srcPt, const Point<uint32_t>& dstPt, const Size& size) {
+ if (size.isEmpty()) {
+ return;
+ }
+
if (!srcImg.valid()) {
throw std::invalid_argument("invalid source for image copy");
}
diff --git a/include/mbgl/util/immutable.hpp b/include/mbgl/util/immutable.hpp
new file mode 100644
index 0000000000..eb26c0d282
--- /dev/null
+++ b/include/mbgl/util/immutable.hpp
@@ -0,0 +1,133 @@
+#pragma once
+
+#include <memory>
+
+namespace mbgl {
+
+/**
+ * `Mutable<T>` is a non-nullable uniquely owning reference to a `T`. It can be efficiently converted
+ * to `Immutable<T>`.
+ *
+ * The lifecycle of `Mutable<T>` and `Immutable<T>` is as follows:
+ *
+ * 1. Create a `Mutable<T>` using `makeMutable(...)`
+ * 2. Mutate it freely
+ * 3. When you're ready to freeze its state and enable safe cross-thread sharing, move assign or
+ * move construct it to `Immutable<T>`
+ *
+ * The reason that `Mutable<T>` exists, rather than simply using a `std::unique_ptr<T>`, is to take advantage
+ * of the underlying single-allocation optimization provided by `std::make_shared`.
+ */
+template <class T>
+class Mutable {
+public:
+ Mutable(Mutable&&) = default;
+ Mutable& operator=(Mutable&&) = default;
+
+ Mutable(const Mutable&) = delete;
+ Mutable& operator=(const Mutable&) = delete;
+
+ T* get() { return ptr.get(); }
+ T* operator->() { return ptr.get(); }
+ T& operator*() { return *ptr; }
+
+private:
+ Mutable(std::shared_ptr<T>&& s)
+ : ptr(std::move(s)) {}
+
+ std::shared_ptr<T> ptr;
+
+ template <class S> friend class Immutable;
+ template <class S, class... Args> friend Mutable<S> makeMutable(Args&&...);
+};
+
+template <class T, class... Args>
+Mutable<T> makeMutable(Args&&... args) {
+ return Mutable<T>(std::make_shared<T>(std::forward<Args>(args)...));
+}
+
+/**
+ * `Immutable<T>` is a non-nullable shared reference to a `const T`. Construction requires
+ * a transfer of unique ownership from a `Mutable<T>`; once constructed it has the same behavior
+ * as `std::shared_ptr<const T>` but with better indication of intent.
+ *
+ * Normally one should not share state between threads because it's difficult to verify the
+ * absence of read/write data races. `Immutable` provides a guarantee that no writes are
+ * possible, and instances therefore can be freely transferred and shared between threads.
+ */
+template <class T>
+class Immutable {
+public:
+ template <class S>
+ Immutable(Mutable<S>&& s)
+ : ptr(std::const_pointer_cast<const S>(std::move(s.ptr))) {}
+
+ template <class S>
+ Immutable(Immutable<S>&& s)
+ : ptr(std::move(s.ptr)) {}
+
+ template <class S>
+ Immutable(const Immutable<S>& s)
+ : ptr(s.ptr) {}
+
+ template <class S>
+ Immutable& operator=(Mutable<S>&& s) {
+ ptr = std::const_pointer_cast<const S>(std::move(s.ptr));
+ return *this;
+ }
+
+ template <class S>
+ Immutable& operator=(Immutable<S>&& s) {
+ ptr = std::move(s.ptr);
+ return *this;
+ }
+
+ template <class S>
+ Immutable& operator=(const Immutable<S>& s) {
+ ptr = s.ptr;
+ return *this;
+ }
+
+ const T* get() const { return ptr.get(); }
+ const T* operator->() const { return ptr.get(); }
+ const T& operator*() const { return *ptr; }
+
+ friend bool operator==(const Immutable<T>& lhs, const Immutable<T>& rhs) {
+ return lhs.ptr == rhs.ptr;
+ }
+
+ friend bool operator!=(const Immutable<T>& lhs, const Immutable<T>& rhs) {
+ return lhs.ptr != rhs.ptr;
+ }
+
+private:
+ Immutable(std::shared_ptr<const T>&& s)
+ : ptr(std::move(s)) {}
+
+ std::shared_ptr<const T> ptr;
+
+ template <class S> friend class Immutable;
+ template <class S, class U> friend Immutable<S> staticImmutableCast(const Immutable<U>&);
+};
+
+template <class S, class U>
+Immutable<S> staticImmutableCast(const Immutable<U>& u) {
+ return Immutable<S>(std::static_pointer_cast<const S>(u.ptr));
+}
+
+/**
+ * Constrained mutation of an immutable reference. Makes a temporarily-mutable copy of the
+ * input Immutable using the inner type's copy constructor, runs the given callable on the
+ * mutable copy, and then freezes the copy and reassigns it to the input reference.
+ *
+ * Note that other Immutables referring to the same inner instance are not affected; they
+ * continue to referencing the original immutable instance.
+ */
+template <class T, class Fn>
+void mutate(Immutable<T>& immutable, Fn&& fn) {
+ Mutable<T> mut = makeMutable<T>(*immutable);
+ std::forward<Fn>(fn)(*mut);
+ immutable = std::move(mut);
+}
+
+} // namespace mbgl
diff --git a/include/mbgl/util/indexed_tuple.hpp b/include/mbgl/util/indexed_tuple.hpp
index a414639530..fd0b931d36 100644
--- a/include/mbgl/util/indexed_tuple.hpp
+++ b/include/mbgl/util/indexed_tuple.hpp
@@ -31,16 +31,13 @@ public:
using std::tuple<Ts...>::tuple;
template <class I>
- static constexpr std::size_t Index = TypeIndex<I, Is...>::value;
-
- template <class I>
auto& get() {
- return std::get<Index<I>>(*this);
+ return std::get<TypeIndex<I, Is...>::value>(*this);
}
template <class I>
const auto& get() const {
- return std::get<Index<I>>(*this);
+ return std::get<TypeIndex<I, Is...>::value>(*this);
}
template <class... Js, class... Us>
diff --git a/include/mbgl/util/interpolate.hpp b/include/mbgl/util/interpolate.hpp
index a2103f18b2..6738987598 100644
--- a/include/mbgl/util/interpolate.hpp
+++ b/include/mbgl/util/interpolate.hpp
@@ -95,7 +95,11 @@ struct Interpolator<std::vector<T>>
: Uninterpolated {};
template <class T>
-constexpr bool Interpolatable = !std::is_base_of<Uninterpolated, Interpolator<T>>::value;
+struct Interpolatable
+ : std::conditional_t<
+ !std::is_base_of<Uninterpolated, Interpolator<T>>::value,
+ std::true_type,
+ std::false_type> {};
} // namespace util
} // namespace mbgl
diff --git a/include/mbgl/util/noncopyable.hpp b/include/mbgl/util/noncopyable.hpp
index 105a76a9a0..8cb7e198d9 100644
--- a/include/mbgl/util/noncopyable.hpp
+++ b/include/mbgl/util/noncopyable.hpp
@@ -7,15 +7,17 @@ namespace non_copyable_
class noncopyable
{
+public:
+ noncopyable( noncopyable const& ) = delete;
+ noncopyable& operator=(noncopyable const& ) = delete;
+
protected:
constexpr noncopyable() = default;
~noncopyable() = default;
- noncopyable( noncopyable const& ) = delete;
- noncopyable& operator=(noncopyable const& ) = delete;
};
} // namespace non_copyable_
-typedef non_copyable_::noncopyable noncopyable;
+using noncopyable = non_copyable_::noncopyable;
} // namespace util
} // namespace mbgl
diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp
index 3cc1146513..f64502c5bc 100644
--- a/include/mbgl/util/projection.hpp
+++ b/include/mbgl/util/projection.hpp
@@ -75,10 +75,7 @@ public:
}
static Point<double> project(const LatLng& latLng, double scale) {
- return Point<double> {
- util::LONGITUDE_MAX + latLng.longitude(),
- util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + latLng.latitude() * M_PI / util::DEGREES_MAX))
- } * worldSize(scale) / util::DEGREES_MAX;
+ return project_(latLng, worldSize(scale));
}
static LatLng unproject(const Point<double>& p, double scale, LatLng::WrapMode wrapMode = LatLng::Unwrapped) {
@@ -89,6 +86,23 @@ public:
wrapMode
};
}
+
+ // Project lat, lon to point in a zoom-dependent world size
+ static Point<double> project(const LatLng& point, uint8_t zoom, uint16_t tileSize) {
+ const double t2z = tileSize * std::pow(2, zoom);
+ Point<double> pt = project_(point, t2z);
+ // Flip y coordinate
+ auto x = std::round(std::min(pt.x, t2z));
+ auto y = std::round(std::min(t2z - pt.y, t2z));
+ return { x, y };
+ }
+private:
+ static Point<double> project_(const LatLng& latLng, double worldSize) {
+ return Point<double> {
+ util::LONGITUDE_MAX + latLng.longitude(),
+ util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + latLng.latitude() * M_PI / util::DEGREES_MAX))
+ } * worldSize / util::DEGREES_MAX;
+ }
};
} // namespace mbgl
diff --git a/include/mbgl/util/range.hpp b/include/mbgl/util/range.hpp
index f7fa92eb8b..5591a22a1f 100644
--- a/include/mbgl/util/range.hpp
+++ b/include/mbgl/util/range.hpp
@@ -1,3 +1,5 @@
+#include <utility>
+
#pragma once
namespace mbgl {
@@ -5,8 +7,8 @@ namespace mbgl {
template <class T>
class Range {
public:
- constexpr Range(const T& min_, const T& max_)
- : min(min_), max(max_) {}
+ constexpr Range(T min_, T max_)
+ : min(std::move(min_)), max(std::move(max_)) {}
T min;
T max;
diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp
index 5236850d83..acbea80273 100644
--- a/include/mbgl/util/run_loop.hpp
+++ b/include/mbgl/util/run_loop.hpp
@@ -16,7 +16,7 @@
namespace mbgl {
namespace util {
-typedef void * LOOP_HANDLE;
+using LOOP_HANDLE = void *;
class RunLoop : public Scheduler,
private util::noncopyable {
@@ -62,14 +62,11 @@ public:
push(task);
return std::make_unique<WorkRequest>(task);
}
-
- // Invoke fn(args...) on this RunLoop, then invoke callback(results...) on the current RunLoop.
- template <class Fn, class... Args>
- std::unique_ptr<AsyncRequest>
- invokeWithCallback(Fn&& fn, Args&&... args) {
- std::shared_ptr<WorkTask> task = WorkTask::makeWithCallback(std::forward<Fn>(fn), std::forward<Args>(args)...);
- push(task);
- return std::make_unique<WorkRequest>(task);
+
+ void schedule(std::weak_ptr<Mailbox> mailbox) override {
+ invoke([mailbox] () {
+ Mailbox::maybeReceive(mailbox);
+ });
}
class Impl;
@@ -81,12 +78,6 @@ private:
void push(std::shared_ptr<WorkTask>);
- void schedule(std::weak_ptr<Mailbox> mailbox) override {
- invoke([mailbox] () {
- Mailbox::maybeReceive(mailbox);
- });
- }
-
void withMutex(std::function<void()>&& fn) {
std::lock_guard<std::mutex> lock(mutex);
fn();
diff --git a/include/mbgl/util/size.hpp b/include/mbgl/util/size.hpp
index 45c303969c..12c0ad056b 100644
--- a/include/mbgl/util/size.hpp
+++ b/include/mbgl/util/size.hpp
@@ -15,6 +15,10 @@ public:
constexpr uint32_t area() const {
return width * height;
}
+
+ constexpr float aspectRatio() const {
+ return static_cast<float>(width) / static_cast<float>(height);
+ }
constexpr bool isEmpty() const {
return width == 0 || height == 0;
diff --git a/include/mbgl/util/string.hpp b/include/mbgl/util/string.hpp
index de061647b5..82d317c620 100644
--- a/include/mbgl/util/string.hpp
+++ b/include/mbgl/util/string.hpp
@@ -1,9 +1,34 @@
#pragma once
+#include <sstream>
#include <string>
#include <cassert>
+#include <cstdlib>
#include <exception>
+// Polyfill needed by Qt when building for Android with GCC
+#if defined(__ANDROID__) && defined(__GLIBCXX__)
+
+namespace std {
+
+template <typename T>
+std::string to_string(T value)
+{
+ std::ostringstream oss;
+ oss << value;
+
+ return oss.str();
+}
+
+inline int stoi(const std::string &str)
+{
+ return atoi(str.c_str());
+}
+
+} // namespace std
+
+#endif
+
namespace mbgl {
namespace util {
diff --git a/include/mbgl/util/thread.hpp b/include/mbgl/util/thread.hpp
new file mode 100644
index 0000000000..672eebf6db
--- /dev/null
+++ b/include/mbgl/util/thread.hpp
@@ -0,0 +1,161 @@
+#pragma once
+
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/actor/mailbox.hpp>
+#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/util.hpp>
+
+#include <cassert>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+#include <utility>
+
+namespace mbgl {
+namespace util {
+
+// Manages a thread with `Object`.
+
+// Upon creation of this object, it launches a thread and creates an object of type `Object`
+// in that thread. When the `Thread<>` object is destructed, the destructor waits
+// for thread termination. The `Thread<>` constructor blocks until the thread and
+// the `Object` are fully created, so after the object creation, it's safe to obtain the
+// `Object` stored in this thread. The thread created will always have low priority on
+// the platforms that support setting thread priority.
+//
+// The following properties make this class different from `ThreadPool`:
+//
+// - Only one thread is created.
+// - `Object` will live in a single thread, providing thread affinity.
+// - It is safe to use `ThreadLocal` in an `Object` managed by `Thread<>`
+// - A `RunLoop` is created for the `Object` thread.
+// - `Object` can use `Timer` and do asynchronous I/O, like wait for sockets events.
+//
+template<class Object>
+class Thread : public Scheduler {
+public:
+ template <class... Args>
+ Thread(const std::string& name, Args&&... args) {
+ std::promise<void> running;
+
+ thread = std::thread([&] {
+ platform::setCurrentThreadName(name);
+ platform::makeThreadLowPriority();
+
+ util::RunLoop loop_(util::RunLoop::Type::New);
+ loop = &loop_;
+
+ object = std::make_unique<Actor<Object>>(*this, std::forward<Args>(args)...);
+ running.set_value();
+
+ loop->run();
+ loop = nullptr;
+ });
+
+ running.get_future().get();
+ }
+
+ ~Thread() override {
+ if (paused) {
+ resume();
+ }
+
+ std::promise<void> joinable;
+
+ // Kill the actor, so we don't get more
+ // messages posted on this scheduler after
+ // we delete the RunLoop.
+ loop->invoke([&] {
+ object.reset();
+ joinable.set_value();
+ });
+
+ joinable.get_future().get();
+
+ loop->stop();
+ thread.join();
+ }
+
+ // Returns a non-owning reference to `Object` that
+ // can be used to send messages to `Object`. It is safe
+ // to the non-owning reference to outlive this object
+ // and be used after the `Thread<>` gets destroyed.
+ ActorRef<std::decay_t<Object>> actor() const {
+ return object->self();
+ }
+
+ // Pauses the `Object` thread. It will prevent the object to wake
+ // up from events such as timers and file descriptor I/O. Messages
+ // sent to a paused `Object` will be queued and only processed after
+ // `resume()` is called.
+ void pause() {
+ MBGL_VERIFY_THREAD(tid);
+
+ assert(!paused);
+
+ paused = std::make_unique<std::promise<void>>();
+ resumed = std::make_unique<std::promise<void>>();
+
+ auto pausing = paused->get_future();
+
+ loop->invoke([this] {
+ auto resuming = resumed->get_future();
+ paused->set_value();
+ resuming.get();
+ });
+
+ pausing.get();
+ }
+
+ // Resumes the `Object` thread previously paused by `pause()`.
+ void resume() {
+ MBGL_VERIFY_THREAD(tid);
+
+ assert(paused);
+
+ resumed->set_value();
+
+ resumed.reset();
+ paused.reset();
+ }
+
+private:
+ MBGL_STORE_THREAD(tid);
+
+ void schedule(std::weak_ptr<Mailbox> mailbox) override {
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+ queue.push(mailbox);
+ }
+
+ loop->invoke([this] { receive(); });
+ }
+
+ void receive() {
+ std::unique_lock<std::mutex> lock(mutex);
+
+ auto mailbox = queue.front();
+ queue.pop();
+ lock.unlock();
+
+ Mailbox::maybeReceive(mailbox);
+ }
+
+ std::mutex mutex;
+ std::queue<std::weak_ptr<Mailbox>> queue;
+ std::thread thread;
+ std::unique_ptr<Actor<Object>> object;
+
+ std::unique_ptr<std::promise<void>> paused;
+ std::unique_ptr<std::promise<void>> resumed;
+
+ util::RunLoop* loop = nullptr;
+};
+
+} // namespace util
+} // namespace mbgl
diff --git a/include/mbgl/util/tileset.hpp b/include/mbgl/util/tileset.hpp
index 1f28a5039a..61aa47d4ea 100644
--- a/include/mbgl/util/tileset.hpp
+++ b/include/mbgl/util/tileset.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/range.hpp>
+#include <mbgl/util/constants.hpp>
#include <vector>
#include <string>
@@ -13,11 +14,25 @@ public:
enum class Scheme : bool { XYZ, TMS };
std::vector<std::string> tiles;
- Range<uint8_t> zoomRange { 0, 22 };
+ Range<uint8_t> zoomRange;
std::string attribution;
- Scheme scheme = Scheme::XYZ;
+ Scheme scheme;
+
+ Tileset(std::vector<std::string> tiles_ = std::vector<std::string>(),
+ Range<uint8_t> zoomRange_ = { 0, util::DEFAULT_MAX_ZOOM },
+ std::string attribution_ = {},
+ Scheme scheme_ = Scheme::XYZ)
+ : tiles(std::move(tiles_)),
+ zoomRange(std::move(zoomRange_)),
+ attribution(std::move(attribution_)),
+ scheme(scheme_) {}
// TileJSON also includes center, zoom, and bounds, but they are not used by mbgl.
+
+ friend bool operator==(const Tileset& lhs, const Tileset& rhs) {
+ return std::tie(lhs.tiles, lhs.zoomRange, lhs.attribution, lhs.scheme)
+ == std::tie(rhs.tiles, rhs.zoomRange, rhs.attribution, rhs.scheme);
+ }
};
} // namespace mbgl
diff --git a/include/mbgl/util/unitbezier.hpp b/include/mbgl/util/unitbezier.hpp
index 3a4994917b..6e644e2d1f 100644
--- a/include/mbgl/util/unitbezier.hpp
+++ b/include/mbgl/util/unitbezier.hpp
@@ -34,11 +34,11 @@ struct UnitBezier {
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
constexpr UnitBezier(double p1x, double p1y, double p2x, double p2y)
: cx(3.0 * p1x)
- , bx(3.0 * (p2x - p1x) - cx)
- , ax(1.0 - cx - bx)
+ , bx(3.0 * (p2x - p1x) - (3.0 * p1x))
+ , ax(1.0 - (3.0 * p1x) - (3.0 * (p2x - p1x) - (3.0 * p1x)))
, cy(3.0 * p1y)
- , by(3.0 * (p2y - p1y) - cy)
- , ay(1.0 - cy - by) {
+ , by(3.0 * (p2y - p1y) - (3.0 * p1y))
+ , ay(1.0 - (3.0 * p1y) - (3.0 * (p2y - p1y) - (3.0 * p1y))) {
}
double sampleCurveX(double t) const {
diff --git a/include/mbgl/util/util.hpp b/include/mbgl/util/util.hpp
index c5a7cb3780..7960b40299 100644
--- a/include/mbgl/util/util.hpp
+++ b/include/mbgl/util/util.hpp
@@ -12,3 +12,10 @@
#define MBGL_VERIFY_THREAD(tid)
#endif
+
+// GCC 4.9 compatibility
+#if !defined(__GNUC__) || __GNUC__ >= 5
+#define MBGL_CONSTEXPR constexpr
+#else
+#define MBGL_CONSTEXPR inline
+#endif
diff --git a/include/mbgl/util/work_task.hpp b/include/mbgl/util/work_task.hpp
index dda8e5d00f..f2dcfcfe86 100644
--- a/include/mbgl/util/work_task.hpp
+++ b/include/mbgl/util/work_task.hpp
@@ -18,9 +18,6 @@ public:
template <class Fn, class... Args>
static std::shared_ptr<WorkTask> make(Fn&&, Args&&...);
-
- template <class Fn, class... Args>
- static std::shared_ptr<WorkTask> makeWithCallback(Fn&&, Args&&...);
};
} // namespace mbgl
diff --git a/include/mbgl/util/work_task_impl.hpp b/include/mbgl/util/work_task_impl.hpp
index 8ebc7d45f8..276e0d6237 100644
--- a/include/mbgl/util/work_task_impl.hpp
+++ b/include/mbgl/util/work_task_impl.hpp
@@ -62,48 +62,4 @@ std::shared_ptr<WorkTask> WorkTask::make(Fn&& fn, Args&&... args) {
flag);
}
-namespace detail {
-template <class Tuple, size_t... Indexes>
-auto packageArgumentsAndCallback(std::shared_ptr<std::atomic<bool>> flag,
- Tuple&& args,
- std::index_sequence<Indexes...>) {
- auto callback = std::get<sizeof...(Indexes)>(args);
-
- // Create a lambda L1 that invokes another lambda L2 on the current RunLoop R, that calls
- // the callback C. Both lambdas check the flag before proceeding. L1 needs to check the flag
- // because if the request was cancelled, then R might have been destroyed. L2 needs to check
- // the flag because the request may have been cancelled after L2 was invoked but before it
- // began executing.
-
- auto l2 = [flag, callback] (auto&&... results) {
- if (!*flag) {
- callback(std::forward<decltype(results)>(results)...);
- }
- };
-
- auto l1 = [flag, current = util::RunLoop::Get(), l2_ = l2] (auto&&... results) {
- if (!*flag) {
- current->invoke(l2_, std::forward<decltype(results)>(results)...);
- }
- };
-
- return std::make_tuple(std::get<Indexes>(std::forward<Tuple>(args))..., l1);
-}
-} // namespace detail
-
-template <class Fn, class... Args>
-std::shared_ptr<WorkTask> WorkTask::makeWithCallback(Fn&& fn, Args&&... args) {
- auto flag = std::make_shared<std::atomic<bool>>();
- *flag = false;
-
- auto tuple = detail::packageArgumentsAndCallback(flag,
- std::forward_as_tuple(std::forward<Args>(args)...),
- std::make_index_sequence<sizeof...(Args) - 1>());
-
- return std::make_shared<WorkTaskImpl<std::decay_t<Fn>, decltype(tuple)>>(
- std::forward<Fn>(fn),
- std::move(tuple),
- flag);
-}
-
} // namespace mbgl