summaryrefslogtreecommitdiff
path: root/src/mbgl/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/util')
-rw-r--r--src/mbgl/util/chrono.cpp11
-rw-r--r--src/mbgl/util/dtoa.cpp16
-rw-r--r--src/mbgl/util/dtoa.hpp1
-rw-r--r--src/mbgl/util/geojson_impl.cpp (renamed from src/mbgl/util/geojson.cpp)0
-rw-r--r--src/mbgl/util/http_header.cpp2
-rw-r--r--src/mbgl/util/i18n.cpp18
-rw-r--r--src/mbgl/util/intersection_tests.cpp2
-rw-r--r--src/mbgl/util/io.cpp6
-rw-r--r--src/mbgl/util/logging.cpp2
-rw-r--r--src/mbgl/util/longest_common_subsequence.hpp106
-rw-r--r--src/mbgl/util/mat2.hpp2
-rw-r--r--src/mbgl/util/mat4.cpp9
-rw-r--r--src/mbgl/util/math.hpp13
-rw-r--r--src/mbgl/util/offscreen_texture.cpp1
-rw-r--r--src/mbgl/util/offscreen_texture.hpp5
-rw-r--r--src/mbgl/util/premultiply.cpp2
-rw-r--r--src/mbgl/util/thread.hpp208
-rw-r--r--src/mbgl/util/thread_context.cpp13
-rw-r--r--src/mbgl/util/thread_context.hpp22
-rw-r--r--src/mbgl/util/thread_local.hpp44
-rw-r--r--src/mbgl/util/work_queue.cpp38
-rw-r--r--src/mbgl/util/work_queue.hpp40
22 files changed, 285 insertions, 276 deletions
diff --git a/src/mbgl/util/chrono.cpp b/src/mbgl/util/chrono.cpp
index 5c8fd3c0ff..a880093b74 100644
--- a/src/mbgl/util/chrono.cpp
+++ b/src/mbgl/util/chrono.cpp
@@ -3,6 +3,13 @@
#include <parsedate/parsedate.h>
#include <cstdio>
+#include <ctime>
+
+#if defined(_WINDOWS)
+#define _gmtime(t, i) gmtime_s(i, t)
+#else
+#define _gmtime(t, i) gmtime_r(t, i)
+#endif
namespace mbgl {
namespace util {
@@ -14,7 +21,7 @@ static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
std::string rfc1123(Timestamp timestamp) {
std::time_t time = std::chrono::system_clock::to_time_t(timestamp);
std::tm info;
- gmtime_r(&time, &info);
+ _gmtime(&time, &info);
char buffer[30];
snprintf(buffer, 30, "%s, %02d %s %4d %02d:%02d:%02d GMT", week[info.tm_wday], info.tm_mday,
months[info.tm_mon], 1900 + info.tm_year, info.tm_hour, info.tm_min, info.tm_sec);
@@ -24,7 +31,7 @@ std::string rfc1123(Timestamp timestamp) {
std::string iso8601(Timestamp timestamp) {
std::time_t time = std::chrono::system_clock::to_time_t(timestamp);
std::tm info;
- gmtime_r(&time, &info);
+ _gmtime(&time, &info);
char buffer[30];
std::strftime(buffer, sizeof(buffer), "%F %T", &info);
return buffer;
diff --git a/src/mbgl/util/dtoa.cpp b/src/mbgl/util/dtoa.cpp
index dd4fba0f89..0e3aef6117 100644
--- a/src/mbgl/util/dtoa.cpp
+++ b/src/mbgl/util/dtoa.cpp
@@ -1,10 +1,18 @@
#include "dtoa.hpp"
+// Clang/C2 on Windows 64-bits can't parse rapidjson's dtoa
+// and it was causing the compiler to crash.
+#if !defined(_WINDOWS)
#include <rapidjson/internal/dtoa.h>
+#endif
+
+#include <mbgl/util/string.hpp>
namespace mbgl {
namespace util {
+#if !defined(_WINDOWS)
+
namespace {
// From https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/internal/dtoa.h
@@ -101,5 +109,13 @@ std::string dtoa(double value) {
return data;
}
+#else
+
+std::string dtoa(double value) {
+ return std::to_string(value);
+}
+
+#endif
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/dtoa.hpp b/src/mbgl/util/dtoa.hpp
index db7d309452..4cb81a94be 100644
--- a/src/mbgl/util/dtoa.hpp
+++ b/src/mbgl/util/dtoa.hpp
@@ -5,7 +5,6 @@
namespace mbgl {
namespace util {
-char* dtoa(double value, char* buffer);
std::string dtoa(double value);
} // end namespace util
diff --git a/src/mbgl/util/geojson.cpp b/src/mbgl/util/geojson_impl.cpp
index d1608e09fe..d1608e09fe 100644
--- a/src/mbgl/util/geojson.cpp
+++ b/src/mbgl/util/geojson_impl.cpp
diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp
index 40711232ff..ce31a06c5e 100644
--- a/src/mbgl/util/http_header.cpp
+++ b/src/mbgl/util/http_header.cpp
@@ -1,5 +1,7 @@
#include <mbgl/util/http_header.hpp>
+#include <mbgl/util/string.hpp>
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wunused-parameter"
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 6cfdc697e3..16f1d669f3 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -15,7 +15,7 @@ namespace {
return codepoint >= first && codepoint <= last; \
}
-// The following table comes from <http://www.unicode.org/Public/9.0.0/ucd/Blocks.txt>.
+// The following table comes from <http://www.unicode.org/Public/10.0.0/ucd/Blocks.txt>.
// Keep it synchronized with <http://www.unicode.org/Public/UCD/latest/ucd/Blocks.txt>.
// DEFINE_IS_IN_UNICODE_BLOCK(BasicLatin, 0x0000, 0x007F)
@@ -37,6 +37,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(ArabicSupplement, 0x0750, 0x077F)
// DEFINE_IS_IN_UNICODE_BLOCK(NKo, 0x07C0, 0x07FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Samaritan, 0x0800, 0x083F)
// DEFINE_IS_IN_UNICODE_BLOCK(Mandaic, 0x0840, 0x085F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Syriac Supplement, 0x0860, 0x086F)
DEFINE_IS_IN_UNICODE_BLOCK(ArabicExtendedA, 0x08A0, 0x08FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Devanagari, 0x0900, 0x097F)
// DEFINE_IS_IN_UNICODE_BLOCK(Bengali, 0x0980, 0x09FF)
@@ -239,9 +240,12 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF)
// DEFINE_IS_IN_UNICODE_BLOCK(Takri, 0x11680, 0x116CF)
// DEFINE_IS_IN_UNICODE_BLOCK(Ahom, 0x11700, 0x1173F)
// DEFINE_IS_IN_UNICODE_BLOCK(WarangCiti, 0x118A0, 0x118FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(ZanabazarSquare, 0x11A00, 0x11A4F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Soyombo, 0x11A50, 0x11AAF)
// DEFINE_IS_IN_UNICODE_BLOCK(PauCinHau, 0x11AC0, 0x11AFF)
// DEFINE_IS_IN_UNICODE_BLOCK(Bhaiksuki, 0x11C00, 0x11C6F)
// DEFINE_IS_IN_UNICODE_BLOCK(Marchen, 0x11C70, 0x11CBF)
+// DEFINE_IS_IN_UNICODE_BLOCK(MasaramGondi, 0x11D00, 0x11D5F)
// DEFINE_IS_IN_UNICODE_BLOCK(Cuneiform, 0x12000, 0x123FF)
// DEFINE_IS_IN_UNICODE_BLOCK(CuneiformNumbersandPunctuation, 0x12400, 0x1247F)
// DEFINE_IS_IN_UNICODE_BLOCK(EarlyDynasticCuneiform, 0x12480, 0x1254F)
@@ -256,6 +260,8 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF)
// DEFINE_IS_IN_UNICODE_BLOCK(Tangut, 0x17000, 0x187FF)
// DEFINE_IS_IN_UNICODE_BLOCK(TangutComponents, 0x18800, 0x18AFF)
// DEFINE_IS_IN_UNICODE_BLOCK(KanaSupplement, 0x1B000, 0x1B0FF)
+// DEFINE_IS_IN_UNICODE_BLOCK(KanaExtendedA, 0x1B100, 0x1B12F)
+// DEFINE_IS_IN_UNICODE_BLOCK(Nushu, 0x1B170, 0x1B2FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Duployan, 0x1BC00, 0x1BC9F)
// DEFINE_IS_IN_UNICODE_BLOCK(ShorthandFormatControls, 0x1BCA0, 0x1BCAF)
// DEFINE_IS_IN_UNICODE_BLOCK(ByzantineMusicalSymbols, 0x1D000, 0x1D0FF)
@@ -286,6 +292,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF)
// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionC, 0x2A700, 0x2B73F)
// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionD, 0x2B740, 0x2B81F)
// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionE, 0x2B820, 0x2CEAF)
+// DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionF, 0x2CEB0, 0x2EBEF)
// DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographsSupplement, 0x2F800, 0x2FA1F)
// DEFINE_IS_IN_UNICODE_BLOCK(Tags, 0xE0000, 0xE007F)
// DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectorsSupplement, 0xE0100, 0xE01EF)
@@ -311,7 +318,7 @@ const std::map<char16_t, char16_t> verticalPunctuation = {
{ u'{', u'︷' }, { u'|', u'―' }, { u'}', u'︸' }, { u'⦅', u'︵' }, { u'⦆', u'︶' },
{ u'。', u'︒' }, { u'「', u'﹁' }, { u'」', u'﹂' },
};
-}
+} // namespace
namespace mbgl {
namespace util {
@@ -375,11 +382,13 @@ bool allowsIdeographicBreaking(char16_t chr) {
// return (isInTangut(chr)
// || isInTangutComponents(chr)
// || isInIdeographicSymbolsandPunctuation(chr)
+ // || isInNushu(chr)
// || isInEnclosedIdeographicSupplement(chr)
// || isInCJKUnifiedIdeographsExtensionB(chr)
// || isInCJKUnifiedIdeographsExtensionC(chr)
// || isInCJKUnifiedIdeographsExtensionD(chr)
// || isInCJKUnifiedIdeographsExtensionE(chr)
+ // || isInCJKUnifiedIdeographsExtensionF(chr)
// || isInCJKCompatibilityIdeographsSupplement(chr));
}
@@ -393,7 +402,7 @@ bool allowsVerticalWritingMode(const std::u16string& string) {
}
// The following logic comes from
-// <http://www.unicode.org/Public/vertical/revision-16/VerticalOrientation-16.txt>.
+// <http://www.unicode.org/Public/vertical/revision-17/VerticalOrientation-17.txt>.
// The data file denotes with “U” or “Tu” any codepoint that may be drawn
// upright in vertical text but does not distinguish between upright and
// “neutral” characters.
@@ -457,6 +466,8 @@ bool hasUprightVerticalOrientation(char16_t chr) {
// if (isInTangut(chr)) return true;
// if (isInTangutComponents(chr)) return true;
// if (isInKanaSupplement(chr)) return true;
+ // if (isInKanaExtendedA(chr)) return true;
+ // if (isInNushu(chr)) return true;
// if (isInByzantineMusicalSymbols(chr)) return true;
// if (isInMusicalSymbols(chr)) return true;
// if (isInTaiXuanJingSymbols(chr)) return true;
@@ -478,6 +489,7 @@ bool hasUprightVerticalOrientation(char16_t chr) {
// if (isInCJKUnifiedIdeographsExtensionC(chr)) return true;
// if (isInCJKUnifiedIdeographsExtensionD(chr)) return true;
// if (isInCJKUnifiedIdeographsExtensionE(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionF(chr)) return true;
// if (isInCJKCompatibilityIdeographsSupplement(chr)) return true;
return false;
diff --git a/src/mbgl/util/intersection_tests.cpp b/src/mbgl/util/intersection_tests.cpp
index c580357298..e6ce245c0e 100644
--- a/src/mbgl/util/intersection_tests.cpp
+++ b/src/mbgl/util/intersection_tests.cpp
@@ -19,7 +19,7 @@ bool polygonContainsPoint(const GeometryCoordinates& ring, const GeometryCoordin
// Code from http://stackoverflow.com/a/1501725/331379.
float distToSegmentSquared(const GeometryCoordinate& p, const GeometryCoordinate& v, const GeometryCoordinate& w) {
if (v == w) return util::distSqr<float>(p, v);
- const float l2 = util::distSqr<float>(v, w);
+ const auto l2 = util::distSqr<float>(v, w);
const float t = float((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
if (t < 0) return util::distSqr<float>(p, v);
if (t > 1) return util::distSqr<float>(p, w);
diff --git a/src/mbgl/util/io.cpp b/src/mbgl/util/io.cpp
index 9adc3b8988..6a6ed7b250 100644
--- a/src/mbgl/util/io.cpp
+++ b/src/mbgl/util/io.cpp
@@ -6,8 +6,6 @@
#include <sstream>
#include <fstream>
-#include <unistd.h>
-
namespace mbgl {
namespace util {
@@ -43,8 +41,8 @@ optional<std::string> readFile(const std::string &filename) {
}
void deleteFile(const std::string& filename) {
- const int ret = unlink(filename.c_str());
- if (ret == -1) {
+ const int ret = std::remove(filename.c_str());
+ if (ret != 0) {
throw IOException(errno, "failed to unlink file");
}
}
diff --git a/src/mbgl/util/logging.cpp b/src/mbgl/util/logging.cpp
index 939f1def64..0552eb36cb 100644
--- a/src/mbgl/util/logging.cpp
+++ b/src/mbgl/util/logging.cpp
@@ -1,6 +1,6 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/enum.hpp>
-#include <mbgl/util/thread.hpp>
+#include <mbgl/util/platform.hpp>
#include <cstdio>
#include <cstdarg>
diff --git a/src/mbgl/util/longest_common_subsequence.hpp b/src/mbgl/util/longest_common_subsequence.hpp
new file mode 100644
index 0000000000..522b5a86b1
--- /dev/null
+++ b/src/mbgl/util/longest_common_subsequence.hpp
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <cstddef>
+#include <functional>
+#include <iterator>
+#include <vector>
+
+namespace mbgl {
+
+/*
+ Computes the longest common subsequence (LCS) of sequences A and B, represented
+ by pairs of random access iterators. The result is output to the provided output
+ iterator. Equality of elements is determined by the provided comparator, defaulting
+ to ==.
+
+ The algorithm used is the O(ND) time and space algorithm from:
+
+ Myers, Eugene W. An O(ND) Difference Algorithm and Its Variations. Algorithmica
+ (1986) 1: 251. http://xmailserver.org/diff2.pdf
+
+ For understanding this algorithm, http://simplygenius.net/Article/DiffTutorial1 is
+ also helpful.
+
+ TODO: implement the O(N) space refinement presented in the paper.
+*/
+template <class InIt, class OutIt, class Equal>
+OutIt longest_common_subsequence(InIt a, InIt endA,
+ InIt b, InIt endB,
+ OutIt outIt,
+ Equal eq) {
+ const std::ptrdiff_t N = endA - a;
+ const std::ptrdiff_t M = endB - b;
+ const std::ptrdiff_t D = N + M;
+
+ if (D == 0) {
+ return outIt;
+ }
+
+ std::vector<std::vector<std::ptrdiff_t>> vs;
+
+ // Self-executing lambda to allow `return` to break from inner loop, and avoid shadowing `v`.
+ [&] () {
+ std::vector<std::ptrdiff_t> v;
+ v.resize(2 * D + 1);
+ v[1] = 0;
+
+ // Core of the algorithm: greedily find farthest-reaching D-paths for increasing
+ // values of D. Store the farthest-reaching endpoints found in each iteration for
+ // later reconstructing the LCS.
+ for (std::ptrdiff_t d = 0; d <= D; ++d) {
+ for (std::ptrdiff_t k = -d; k <= d; k += 2) {
+ std::ptrdiff_t x = (k == -d || (k != d && v.at(k - 1 + D) < v.at(k + 1 + D)))
+ ? v.at(k + 1 + D) // moving down
+ : v.at(k - 1 + D) + 1; // moving right
+
+ std::ptrdiff_t y = x - k;
+
+ while (x < N && y < M && eq(a[x], b[y])) {
+ x++;
+ y++;
+ }
+
+ v[k + D] = x;
+
+ if (x >= N && y >= M) {
+ vs.push_back(v);
+ return;
+ }
+ }
+
+ vs.push_back(v);
+ }
+ }();
+
+ std::ptrdiff_t x = N;
+ std::ptrdiff_t y = M;
+
+ using E = typename std::iterator_traits<InIt>::value_type;
+ std::vector<E> lcsReverse;
+
+ // Reconstruct the LCS using the farthest-reaching endpoints stored above.
+ for (std::ptrdiff_t d = vs.size() - 1; x > 0 || y > 0; --d) {
+ const std::vector<std::ptrdiff_t>& v = vs.at(d);
+ const std::ptrdiff_t k = x - y;
+ const bool down = (k == -d || (k != d && v.at(k - 1 + D) < v.at(k + 1 + D)));
+ const std::ptrdiff_t kPrev = down ? k + 1 : k - 1;
+
+ x = v.at(kPrev + D);
+ y = x - kPrev;
+
+ for (std::ptrdiff_t c = v[k + D]; c != (down ? x : x + 1); --c) {
+ lcsReverse.push_back(a[c - 1]);
+ }
+ }
+
+ return std::copy(lcsReverse.rbegin(), lcsReverse.rend(), outIt);
+}
+
+template < typename InIt, typename OutIt >
+OutIt longest_common_subsequence(InIt a, InIt endA,
+ InIt b, InIt endB,
+ OutIt outIt) {
+ return longest_common_subsequence(a, endA, b, endB, outIt, std::equal_to<>());
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/util/mat2.hpp b/src/mbgl/util/mat2.hpp
index 6a25ef0f1e..c463202daa 100644
--- a/src/mbgl/util/mat2.hpp
+++ b/src/mbgl/util/mat2.hpp
@@ -26,7 +26,7 @@
namespace mbgl {
-typedef std::array<double, 4> mat2;
+using mat2 = std::array<double, 4>;
namespace matrix {
diff --git a/src/mbgl/util/mat4.cpp b/src/mbgl/util/mat4.cpp
index d3d3617b7b..0ad0d371e5 100644
--- a/src/mbgl/util/mat4.cpp
+++ b/src/mbgl/util/mat4.cpp
@@ -336,10 +336,11 @@ void multiply(mat4& out, const mat4& a, const mat4& b) {
}
void transformMat4(vec4& out, const vec4& a, const mat4& m) {
- out[0] = m[0] * a[0] + m[4] * a[1] + m[8] * a[2] + m[12] * a[3];
- out[1] = m[1] * a[0] + m[5] * a[1] + m[9] * a[2] + m[13] * a[3];
- out[2] = m[2] * a[0] + m[6] * a[1] + m[10] * a[2] + m[14] * a[3];
- out[3] = m[3] * a[0] + m[7] * a[1] + m[11] * a[2] + m[15] * a[3];
+ double x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
}
} // namespace matrix
diff --git a/src/mbgl/util/math.hpp b/src/mbgl/util/math.hpp
index f969ecaedd..fcde01c1a3 100644
--- a/src/mbgl/util/math.hpp
+++ b/src/mbgl/util/math.hpp
@@ -106,5 +106,18 @@ T smoothstep(T edge0, T edge1, T x) {
return t * t * (T(3) - T(2) * t);
}
+template <typename T>
+inline T division(const T dividend, const T divisor, const T nan) {
+ if (divisor == 0) {
+ if (dividend == 0) {
+ return nan;
+ } else {
+ return ::copysign(std::numeric_limits<T>::infinity(), dividend);
+ }
+ } else {
+ return dividend / divisor;
+ }
+}
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp
index fe24774b7c..77a1416e48 100644
--- a/src/mbgl/util/offscreen_texture.cpp
+++ b/src/mbgl/util/offscreen_texture.cpp
@@ -33,6 +33,7 @@ public:
}
context.activeTexture = 0;
+ context.scissorTest = false;
context.viewport = { 0, 0, size };
}
diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp
index ae96286340..0353f3f9c5 100644
--- a/src/mbgl/util/offscreen_texture.hpp
+++ b/src/mbgl/util/offscreen_texture.hpp
@@ -1,6 +1,5 @@
#pragma once
-#include <mbgl/map/view.hpp>
#include <mbgl/util/image.hpp>
namespace mbgl {
@@ -15,7 +14,7 @@ enum class OffscreenTextureAttachment {
Depth,
};
-class OffscreenTexture : public View {
+class OffscreenTexture {
public:
OffscreenTexture(gl::Context&,
Size size = { 256, 256 },
@@ -24,7 +23,7 @@ public:
OffscreenTexture(OffscreenTexture&&);
OffscreenTexture& operator=(OffscreenTexture&&);
- void bind() override;
+ void bind();
PremultipliedImage readStillImage();
diff --git a/src/mbgl/util/premultiply.cpp b/src/mbgl/util/premultiply.cpp
index 219273d7cc..d9fb2480de 100644
--- a/src/mbgl/util/premultiply.cpp
+++ b/src/mbgl/util/premultiply.cpp
@@ -9,6 +9,7 @@ PremultipliedImage premultiply(UnassociatedImage&& src) {
PremultipliedImage dst;
dst.size = src.size;
+ src.size = { 0, 0 };
dst.data = std::move(src.data);
uint8_t* data = dst.data.get();
@@ -29,6 +30,7 @@ UnassociatedImage unpremultiply(PremultipliedImage&& src) {
UnassociatedImage dst;
dst.size = src.size;
+ src.size = { 0, 0 };
dst.data = std::move(src.data);
uint8_t* data = dst.data.get();
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
index 184c6a8a12..572f46080e 100644
--- a/src/mbgl/util/thread.hpp
+++ b/src/mbgl/util/thread.hpp
@@ -1,63 +1,100 @@
#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 <atomic>
#include <utility>
-#include <functional>
-
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/thread_context.hpp>
-#include <mbgl/util/platform.hpp>
-#include <mbgl/util/util.hpp>
namespace mbgl {
namespace util {
-// Manages a thread with Object.
-
-// Upon creation of this object, it launches a thread, creates an object of type Object in that
-// thread, and then calls .start(); on that object. When the Thread<> object is destructed, the
-// Object's .stop() function is called, and 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.
-
-template <class Object>
-class Thread {
+// 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 ThreadContext&, Args&&... args);
- ~Thread();
+ Thread(const std::string& name, Args&&... args) {
+ std::promise<void> running;
- // Invoke object->fn(args...) asynchronously.
- template <typename Fn, class... Args>
- void invoke(Fn fn, Args&&... args) {
- loop->invoke(bind(fn), std::forward<Args>(args)...);
- }
+ thread = std::thread([&] {
+ platform::setCurrentThreadName(name);
+ platform::makeThreadLowPriority();
+
+ util::RunLoop loop_(util::RunLoop::Type::New);
+ loop = &loop_;
- // Invoke object->fn(args...) asynchronously. The final argument to fn must be a callback.
- // The provided callback is wrapped such that it is invoked, in the current thread (which
- // must have a RunLoop), once for each time the invocation of fn invokes the wrapper, each
- // time forwarding the passed arguments, until such time as the AsyncRequest is cancelled.
- template <typename Fn, class... Args>
- std::unique_ptr<AsyncRequest>
- invokeWithCallback(Fn fn, Args&&... args) {
- return loop->invokeWithCallback(bind(fn), std::forward<Args>(args)...);
+ object = std::make_unique<Actor<Object>>(*this, std::forward<Args>(args)...);
+ running.set_value();
+
+ loop->run();
+ loop = nullptr;
+ });
+
+ running.get_future().get();
}
- // Invoke object->fn(args...) asynchronously, but wait for the result.
- template <typename Fn, class... Args>
- auto invokeSync(Fn fn, Args&&... args) {
- assert(!paused);
+ ~Thread() override {
+ MBGL_VERIFY_THREAD(tid);
+
+ 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();
- using R = std::result_of_t<Fn(Object, Args&&...)>;
- std::packaged_task<R ()> task(std::bind(fn, object, args...));
- std::future<R> future = task.get_future();
- loop->invoke(std::move(task));
- return 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);
@@ -77,6 +114,7 @@ public:
pausing.get();
}
+ // Resumes the `Object` thread previously paused by `pause()`.
void resume() {
MBGL_VERIFY_THREAD(tid);
@@ -91,83 +129,35 @@ public:
private:
MBGL_STORE_THREAD(tid);
- Thread(const Thread&) = delete;
- Thread(Thread&&) = delete;
- Thread& operator=(const Thread&) = delete;
- Thread& operator=(Thread&&) = delete;
+ void schedule(std::weak_ptr<Mailbox> mailbox) override {
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+ queue.push(mailbox);
+ }
- template <typename Fn>
- auto bind(Fn fn) {
- return [fn, this] (auto &&... args) {
- return (object->*fn)(std::forward<decltype(args)>(args)...);
- };
+ loop->invoke([this] { receive(); });
}
- template <typename P, std::size_t... I>
- void run(P&& params, std::index_sequence<I...>);
+ void receive() {
+ std::unique_lock<std::mutex> lock(mutex);
- std::promise<void> running;
- std::promise<void> joinable;
+ auto mailbox = queue.front();
+ queue.pop();
+ lock.unlock();
- std::unique_ptr<std::promise<void>> paused;
- std::unique_ptr<std::promise<void>> resumed;
+ Mailbox::maybeReceive(mailbox);
+ }
+ std::mutex mutex;
+ std::queue<std::weak_ptr<Mailbox>> queue;
std::thread thread;
+ std::unique_ptr<Actor<Object>> object;
- Object* object = nullptr;
- RunLoop* loop = nullptr;
-};
-
-template <class Object>
-template <class... Args>
-Thread<Object>::Thread(const ThreadContext& context, Args&&... args) {
- // Note: We're using std::tuple<> to store the arguments because GCC 4.9 has a bug
- // when expanding parameters packs captured in lambdas.
- std::tuple<Args...> params = std::forward_as_tuple(::std::forward<Args>(args)...);
-
- thread = std::thread([&] {
- platform::setCurrentThreadName(context.name);
-
- if (context.priority == ThreadPriority::Low) {
- platform::makeThreadLowPriority();
- }
-
- run(std::move(params), std::index_sequence_for<Args...>{});
- });
-
- running.get_future().get();
-}
-
-template <class Object>
-template <typename P, std::size_t... I>
-void Thread<Object>::run(P&& params, std::index_sequence<I...>) {
- RunLoop loop_(RunLoop::Type::New);
- loop = &loop_;
-
- Object object_(std::get<I>(std::forward<P>(params))...);
- object = &object_;
-
- running.set_value();
- loop_.run();
-
- loop = nullptr;
- object = nullptr;
-
- joinable.get_future().get();
-}
-
-template <class Object>
-Thread<Object>::~Thread() {
- MBGL_VERIFY_THREAD(tid);
-
- if (paused) {
- resume();
- }
+ std::unique_ptr<std::promise<void>> paused;
+ std::unique_ptr<std::promise<void>> resumed;
- loop->stop();
- joinable.set_value();
- thread.join();
-}
+ util::RunLoop* loop = nullptr;
+};
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/thread_context.cpp b/src/mbgl/util/thread_context.cpp
deleted file mode 100644
index fe64c2a686..0000000000
--- a/src/mbgl/util/thread_context.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <mbgl/util/thread_context.hpp>
-#include <utility>
-
-namespace mbgl {
-namespace util {
-
-ThreadContext::ThreadContext(std::string name_, ThreadPriority priority_)
- : name(std::move(name_)),
- priority(priority_) {
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/thread_context.hpp b/src/mbgl/util/thread_context.hpp
deleted file mode 100644
index a51dede404..0000000000
--- a/src/mbgl/util/thread_context.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include <string>
-
-namespace mbgl {
-namespace util {
-
-enum class ThreadPriority : bool {
- Regular,
- Low,
-};
-
-struct ThreadContext {
-public:
- ThreadContext(std::string name, ThreadPriority priority = ThreadPriority::Regular);
-
- std::string name;
- ThreadPriority priority;
-};
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/thread_local.hpp b/src/mbgl/util/thread_local.hpp
index 9fddbd5bbc..b0e26356b4 100644
--- a/src/mbgl/util/thread_local.hpp
+++ b/src/mbgl/util/thread_local.hpp
@@ -1,12 +1,8 @@
#pragma once
-#include <mbgl/util/logging.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <cassert>
-#include <stdexcept>
-
-#include <pthread.h>
+#include <memory>
namespace mbgl {
namespace util {
@@ -14,40 +10,20 @@ namespace util {
template <class T>
class ThreadLocal : public noncopyable {
public:
- ThreadLocal() {
- int ret = pthread_key_create(&key, [](void *ptr) {
- delete reinterpret_cast<T *>(ptr);
- });
-
- if (ret) {
- throw std::runtime_error("Failed to init local storage key.");
- }
- }
-
- ~ThreadLocal() {
- if (pthread_key_delete(key)) {
- Log::Error(Event::General, "Failed to delete local storage key.");
- assert(false);
- }
+ ThreadLocal(T* val) {
+ ThreadLocal();
+ set(val);
}
- T* get() {
- T* ret = reinterpret_cast<T*>(pthread_getspecific(key));
- if (!ret) {
- return nullptr;
- }
+ ThreadLocal();
+ ~ThreadLocal();
- return ret;
- }
-
- void set(T* ptr) {
- if (pthread_setspecific(key, ptr)) {
- throw std::runtime_error("Failed to set local storage.");
- }
- }
+ T* get();
+ void set(T* ptr);
private:
- pthread_key_t key;
+ class Impl;
+ std::unique_ptr<Impl> impl;
};
} // namespace util
diff --git a/src/mbgl/util/work_queue.cpp b/src/mbgl/util/work_queue.cpp
deleted file mode 100644
index d0033e3ca2..0000000000
--- a/src/mbgl/util/work_queue.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <mbgl/util/work_queue.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <cassert>
-
-namespace mbgl {
-namespace util {
-
-WorkQueue::WorkQueue() : runLoop(RunLoop::Get()) {
-}
-
-WorkQueue::~WorkQueue() {
- assert(runLoop == RunLoop::Get());
-
- // Cancel all pending AsyncRequests.
- while (!queue.empty()) {
- queue.pop();
- }
-}
-
-void WorkQueue::push(std::function<void()>&& fn) {
- std::lock_guard<std::mutex> lock(queueMutex);
-
- auto workRequest = runLoop->invokeCancellable(std::bind(&WorkQueue::pop, this, std::move(fn)));
- queue.push(std::move(workRequest));
-}
-
-void WorkQueue::pop(const std::function<void()>& fn) {
- assert(runLoop == RunLoop::Get());
-
- fn();
-
- std::lock_guard<std::mutex> lock(queueMutex);
- queue.pop();
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/work_queue.hpp b/src/mbgl/util/work_queue.hpp
deleted file mode 100644
index 3f6328fb57..0000000000
--- a/src/mbgl/util/work_queue.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/async_request.hpp>
-
-#include <functional>
-#include <memory>
-#include <mutex>
-#include <queue>
-
-namespace mbgl {
-namespace util {
-
-class RunLoop;
-
-// The WorkQueue will manage a queue of closures
-// and it will make sure they get executed on the
-// thread that created the WorkQueue. All pending
-// works are canceled when the queue gets destructed.
-class WorkQueue : private util::noncopyable {
-public:
- WorkQueue();
- ~WorkQueue();
-
- // Push a closure to the queue. It is advised to
- // only push tasks calling functions on the object
- // that owns the queue to avoid use after free errors.
- void push(std::function<void()>&&);
-
-private:
- void pop(const std::function<void()>&);
-
- std::queue<std::unique_ptr<AsyncRequest>> queue;
- std::mutex queueMutex;
-
- RunLoop* runLoop;
-};
-
-} // namespace util
-} // namespace mbgl