From 4ea281c750c5afcc68f2832bb42d98a1cbce6735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 16 Jul 2014 18:53:56 -0700 Subject: rename llmr => mbgl --- include/mbgl/util/clip_ids.hpp | 19 + include/mbgl/util/constants.hpp | 33 ++ include/mbgl/util/enum.hpp | 55 +++ include/mbgl/util/error.hpp | 20 + include/mbgl/util/image.hpp | 36 ++ include/mbgl/util/io.hpp | 15 + include/mbgl/util/mat4.hpp | 45 ++ include/mbgl/util/math.hpp | 115 +++++ include/mbgl/util/noncopyable.hpp | 23 + include/mbgl/util/pbf.hpp | 184 ++++++++ include/mbgl/util/raster.hpp | 70 +++ include/mbgl/util/rect.hpp | 21 + include/mbgl/util/recursive_wrapper.hpp | 127 ++++++ include/mbgl/util/std.hpp | 38 ++ include/mbgl/util/string.hpp | 24 ++ include/mbgl/util/texturepool.hpp | 25 ++ include/mbgl/util/threadpool.hpp | 45 ++ include/mbgl/util/time.hpp | 42 ++ include/mbgl/util/timer.hpp | 40 ++ include/mbgl/util/token.hpp | 52 +++ include/mbgl/util/transition.hpp | 84 ++++ include/mbgl/util/unitbezier.hpp | 121 ++++++ include/mbgl/util/utf.hpp | 50 +++ include/mbgl/util/uv.hpp | 141 ++++++ include/mbgl/util/variant.hpp | 731 ++++++++++++++++++++++++++++++++ include/mbgl/util/vec.hpp | 117 +++++ 26 files changed, 2273 insertions(+) create mode 100644 include/mbgl/util/clip_ids.hpp create mode 100644 include/mbgl/util/constants.hpp create mode 100644 include/mbgl/util/enum.hpp create mode 100644 include/mbgl/util/error.hpp create mode 100644 include/mbgl/util/image.hpp create mode 100644 include/mbgl/util/io.hpp create mode 100644 include/mbgl/util/mat4.hpp create mode 100644 include/mbgl/util/math.hpp create mode 100644 include/mbgl/util/noncopyable.hpp create mode 100644 include/mbgl/util/pbf.hpp create mode 100644 include/mbgl/util/raster.hpp create mode 100644 include/mbgl/util/rect.hpp create mode 100644 include/mbgl/util/recursive_wrapper.hpp create mode 100644 include/mbgl/util/std.hpp create mode 100644 include/mbgl/util/string.hpp create mode 100644 include/mbgl/util/texturepool.hpp create mode 100644 include/mbgl/util/threadpool.hpp create mode 100644 include/mbgl/util/time.hpp create mode 100644 include/mbgl/util/timer.hpp create mode 100644 include/mbgl/util/token.hpp create mode 100644 include/mbgl/util/transition.hpp create mode 100644 include/mbgl/util/unitbezier.hpp create mode 100644 include/mbgl/util/utf.hpp create mode 100644 include/mbgl/util/uv.hpp create mode 100644 include/mbgl/util/variant.hpp create mode 100644 include/mbgl/util/vec.hpp (limited to 'include/mbgl/util') diff --git a/include/mbgl/util/clip_ids.hpp b/include/mbgl/util/clip_ids.hpp new file mode 100644 index 0000000000..748d3d8f5f --- /dev/null +++ b/include/mbgl/util/clip_ids.hpp @@ -0,0 +1,19 @@ +#ifndef MBGL_UTIL_CLIP_IDS +#define MBGL_UTIL_CLIP_IDS + +#include +#include +#include +#include + +namespace mbgl { + +static constexpr uint8_t clipMask[9] { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF }; + +void updateClipIDs(const std::list &array); + +std::map computeClipIDs(std::forward_list array); + +} + +#endif diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp new file mode 100644 index 0000000000..89e8af2ef1 --- /dev/null +++ b/include/mbgl/util/constants.hpp @@ -0,0 +1,33 @@ +#ifndef MBGL_UTIL_CONSTANTS +#define MBGL_UTIL_CONSTANTS + +#include + +#include "vec.hpp" + +namespace mbgl { + +namespace util { + +extern const float tileSize; + +} + +namespace debug { + +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; +extern const bool glyphWarning; +extern const bool shapingWarning; + +} + +} + +#endif diff --git a/include/mbgl/util/enum.hpp b/include/mbgl/util/enum.hpp new file mode 100644 index 0000000000..195aaab5a5 --- /dev/null +++ b/include/mbgl/util/enum.hpp @@ -0,0 +1,55 @@ +#ifndef MBGL_UTIL_ENUM +#define MBGL_UTIL_ENUM + +#include +#include + +namespace mbgl { + +template +struct EnumValue { + const Type value; + const char *name; +}; + +template *names, const size_t length> +struct Enum { + using Type = EnumName; + Type value; + static const constexpr size_t l = length; +private: + static constexpr inline bool compare(const char *a, const char *b) { + return *a == *b && (*a == '\0' || compare(a + 1, b + 1)); + } + static constexpr inline const char *lookup_type(Type e, EnumValue const * const l, size_t r) { + return r == 0 ? "" : l->value == e ? l->name : lookup_type(e, l + 1, r - 1); + } + static constexpr inline Type lookup_name(const char *n, EnumValue const * const l, size_t r) { + return r == 0 ? Type(-1) : compare(l->name, n) ? l->value : lookup_name(n, l + 1, r - 1); + } +public: + inline constexpr Enum(const char *n) : value(lookup_name(n, names, length)) {} + inline constexpr Enum(const std::string &n) : value(lookup_name(n.c_str(), names, length)) {} + inline constexpr Enum(Type t) : value(t) {} + + inline void operator=(const char *n) { value = lookup_name(n, names, length); } + inline void operator=(const std::string &n) { *this = n.c_str(); } + inline void operator=(Type t) { value = t; } + + inline constexpr bool valid() const { return value != Type(-1); } + + inline constexpr const char *c_str() const { return lookup_type(value, names, length); } + inline std::string str() const { return c_str(); } + + inline constexpr operator Type() const { return value; } +}; + +#define MBGL_DEFINE_ENUM_CLASS(name, type, strings...) \ + const constexpr ::mbgl::EnumValue type##_names[] = strings; \ + using name = ::mbgl::Enum)>; \ + inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); } + +} + +#endif + diff --git a/include/mbgl/util/error.hpp b/include/mbgl/util/error.hpp new file mode 100644 index 0000000000..99e27f770c --- /dev/null +++ b/include/mbgl/util/error.hpp @@ -0,0 +1,20 @@ +#ifndef MBGL_UTIL_ERROR +#define MBGL_UTIL_ERROR + +#include +#include + +namespace mbgl { +namespace error { + +struct style_parse : std::exception { + inline style_parse(size_t offset, const char *msg) : offset(offset), msg(msg) {} + inline const char* what() const noexcept { return msg.c_str(); } + const size_t offset; + const std::string msg; +}; +} + +} + +#endif \ No newline at end of file diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp new file mode 100644 index 0000000000..dc8f6a8150 --- /dev/null +++ b/include/mbgl/util/image.hpp @@ -0,0 +1,36 @@ +#ifndef MBGL_UTIL_IMAGE +#define MBGL_UTIL_IMAGE + +#include +#include +#include + +namespace mbgl { +namespace util { + +std::string compress_png(int width, int height, void *rgba, bool flip = false); + + +class Image { +public: + Image(const std::string &img, bool flip = false); + ~Image(); + + inline const char *getData() const { return img; } + inline uint32_t getWidth() const { return width; } + inline uint32_t getHeight() const { return height; } + +private: + // loaded image dimensions + uint32_t width = 0, height = 0; + + // the raw image data + char *img = nullptr; + +}; + + +} +} + +#endif diff --git a/include/mbgl/util/io.hpp b/include/mbgl/util/io.hpp new file mode 100644 index 0000000000..e95fc16d9d --- /dev/null +++ b/include/mbgl/util/io.hpp @@ -0,0 +1,15 @@ +#ifndef MBGL_UTIL_IO +#define MBGL_UTIL_IO + +#include + +namespace mbgl { +namespace util { + +void write_file(const std::string &filename, const std::string &data); +std::string read_file(const std::string &filename); + +} +} + +#endif diff --git a/include/mbgl/util/mat4.hpp b/include/mbgl/util/mat4.hpp new file mode 100644 index 0000000000..4279113d21 --- /dev/null +++ b/include/mbgl/util/mat4.hpp @@ -0,0 +1,45 @@ +// This is an incomplete port of http://glmatrix.net/ +// +// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim +// that you wrote the original software. If you use this software in a +// product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef MBGL_UTIL_MAT4 +#define MBGL_UTIL_MAT4 + +#include + +namespace mbgl { + +typedef std::array mat4; + +namespace matrix { + +void identity(mat4& out); +void ortho(mat4& out, float left, float right, float bottom, float top, float near, float far); +void copy(mat4& out, const mat4& a); +void translate(mat4& out, const mat4& a, float x, float y, float z); +void rotate_z(mat4& out, const mat4& a, float rad); +void scale(mat4& out, const mat4& a, float x, float y, float z); +void multiply(mat4& out, const mat4& a, const mat4& b); + +} +} + +#endif diff --git a/include/mbgl/util/math.hpp b/include/mbgl/util/math.hpp new file mode 100644 index 0000000000..277fdc8fc3 --- /dev/null +++ b/include/mbgl/util/math.hpp @@ -0,0 +1,115 @@ +#ifndef MBGL_UTIL_MATH +#define MBGL_UTIL_MATH + +#include +#include + +#include "vec.hpp" + +namespace mbgl { +namespace util { + + +template +inline T max(T a, T b) { + return b > a ? b : a; +} + +template +inline T max(T a, T b, T c) { + return max(max(a, b), c); +} + +template +inline T max(T a, T b, T c, T d) { + return max(max(a, b), max(c, d)); +} + +template +inline T min(T a, T b) { + return b < a ? b : a; +} + +template +inline T min(T a, T b, T c) { + return min(min(a, b), c); +} + +template +inline T min(T a, T b, T c, T d) { + return min(min(a, b), min(c, d)); +} + +// Find the angle of the two vectors, solving the formula for the cross product +// a x b = |a||b|sin(θ) for θ. +template +inline T angle_between(S ax, S ay, S bx, S by) { + return std::atan2((ax * by - ay * bx), ax * bx + ay * by); +} + +template +inline T angle_between(const vec2& a, const vec2& b) { + return angle_between(a.x, a.y, b.x, b.y); +} + +template +inline T angle_to(const vec2& a, const vec2& b) { + return std::atan2(a.y - b.y, a.x - b.x); +} + +template +inline T interp(S1 a, S2 b, T t) { + return (a * ((T)1 - t)) + (b * t); +} + +// Reflect an angle around 0 degrees +template +inline std::array flip(const std::array& c) { + return {{ + static_cast(2 * M_PI - c[0]), + static_cast(2 * M_PI - c[1]) + }}; +} + +template +inline vec2 normal(const S1& a, const S2& b) { + T dx = b.x - a.x; + T dy = b.y - a.y; + T c = std::sqrt(dx * dx + dy * dy); + return { dx / c, dy / c }; +} + +template +inline T dist(const S1& a, const S2& b) { + T dx = b.x - a.x; + T dy = b.y - a.y; + T c = std::sqrt(dx * dx + dy * dy); + return c; +} + +template +inline T length(T a, T b) { + return std::sqrt(a * a + b * b); +} + +// Take the magnitude of vector a. +template +inline T mag(const S& a) { + return std::sqrt(a.x * a.x + a.y * a.y); +} + +template +T clamp(T value, T min, T max) { + return value < min ? min : (value > max ? max : value); +} + +template +T smoothstep(T edge0, T edge1, T x) { + T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1)); + return t * t * (T(3) - T(2) * t); +} + +} +} + +#endif diff --git a/include/mbgl/util/noncopyable.hpp b/include/mbgl/util/noncopyable.hpp new file mode 100644 index 0000000000..ada701efc6 --- /dev/null +++ b/include/mbgl/util/noncopyable.hpp @@ -0,0 +1,23 @@ +#ifndef MBGL_UTIL_NONCOPYABLE +#define MBGL_UTIL_NONCOPYABLE + +namespace mbgl { namespace util { + +namespace non_copyable_ +{ + +class noncopyable +{ +protected: + constexpr noncopyable() = default; + ~noncopyable() = default; + noncopyable( noncopyable const& ) = delete; + noncopyable& operator=(noncopyable const& ) = delete; +}; +} + +typedef non_copyable_::noncopyable noncopyable; + +}} + +#endif diff --git a/include/mbgl/util/pbf.hpp b/include/mbgl/util/pbf.hpp new file mode 100644 index 0000000000..1f78a0072f --- /dev/null +++ b/include/mbgl/util/pbf.hpp @@ -0,0 +1,184 @@ +#ifndef MBGL_UTIL_PBF +#define MBGL_UTIL_PBF + +/* + * Some parts are from upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2008-2011 Google Inc. See LICENSE for details. + * Author: Josh Haberman + */ + +#include +#include + +namespace mbgl { + +struct pbf { + struct exception : std::exception { const char *what() const noexcept { return "pbf exception"; } }; + struct unterminated_varint_exception : exception { const char *what() const noexcept { return "pbf unterminated varint exception"; } }; + struct varint_too_long_exception : exception { const char *what() const noexcept { return "pbf varint too long exception"; } }; + struct unknown_field_type_exception : exception { const char *what() const noexcept { return "pbf unknown field type exception"; } }; + struct end_of_buffer_exception : exception { const char *what() const noexcept { return "pbf end of buffer exception"; } }; + + inline pbf(const unsigned char *data, size_t length); + inline pbf(); + + inline operator bool() const; + + inline bool next(); + inline bool next(uint32_t tag); + template inline T varint(); + template inline T svarint(); + + template inline T fixed(); + inline float float32(); + inline double float64(); + + inline std::string string(); + inline bool boolean(); + + inline pbf message(); + + inline void skip(); + inline void skipValue(uint32_t val); + inline void skipBytes(uint32_t bytes); + + const uint8_t *data = nullptr; + const uint8_t *end = nullptr; + uint32_t value = 0; + uint32_t tag = 0; +}; + +pbf::pbf(const unsigned char *data, size_t length) + : data(data), + end(data + length), + value(0), + tag(0) { +} + +pbf::pbf() + : data(nullptr), + end(nullptr), + value(0), + tag(0) { +} + + +pbf::operator bool() const { + return data < end; +} + +bool pbf::next() { + if (data < end) { + value = static_cast(varint()); + tag = value >> 3; + return true; + } + return false; +} + +bool pbf::next(uint32_t requested_tag) { + while (next()) { + if (tag == requested_tag) { + return true; + } else { + skip(); + } + } + return false; +} + +template +T pbf::varint() { + uint8_t byte = 0x80; + T result = 0; + int bitpos; + for (bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) { + if (data >= end) { + throw unterminated_varint_exception(); + } + result |= ((T)(byte = *data) & 0x7F) << bitpos; + + data++; + } + if (bitpos == 70 && (byte & 0x80)) { + throw varint_too_long_exception(); + } + + return result; +} + +template +T pbf::svarint() { + T n = varint(); + return (n >> 1) ^ -(T)(n & 1); +} + +template +T pbf::fixed() { + skipBytes(bytes); + T result; + memcpy(&result, data - bytes, bytes); + return result; +} + +float pbf::float32() { + return fixed(); +} + +double pbf::float64() { + return fixed(); +} + +std::string pbf::string() { + uint32_t bytes = static_cast(varint()); + const char *string = reinterpret_cast(data); + skipBytes(bytes); + return std::string(string, bytes); +} + +bool pbf::boolean() { + skipBytes(1); + return *(bool *)(data - 1); +} + +pbf pbf::message() { + uint32_t bytes = static_cast(varint()); + const uint8_t *pos = data; + skipBytes(bytes); + return pbf(pos, bytes); +} + +void pbf::skip() { + skipValue(value); +} + +void pbf::skipValue(uint32_t val) { + switch (val & 0x7) { + case 0: // varint + varint(); + break; + case 1: // 64 bit + skipBytes(8); + break; + case 2: // string/message + skipBytes(static_cast(varint())); + break; + case 5: // 32 bit + skipBytes(4); + break; + default: + throw unknown_field_type_exception(); + } +} + +void pbf::skipBytes(uint32_t bytes) { + if (data + bytes > end) { + throw end_of_buffer_exception(); + } + data += bytes; +} + +} // end namespace mbgl + +#endif diff --git a/include/mbgl/util/raster.hpp b/include/mbgl/util/raster.hpp new file mode 100644 index 0000000000..04c85169e2 --- /dev/null +++ b/include/mbgl/util/raster.hpp @@ -0,0 +1,70 @@ +#ifndef MBGL_UTIL_RASTER +#define MBGL_UTIL_RASTER + +#include +#include +#include + +#include +#include +#include + +typedef struct uv_loop_s uv_loop_t; + +namespace mbgl { + +class Raster : public std::enable_shared_from_this { + +public: + Raster(const std::shared_ptr &texturepool); + ~Raster(); + + // load image data + bool load(const std::string &img); + + // bind current texture + void bind(bool linear = false); + + // loaded status + bool isLoaded() const; + + // transitions + void beginFadeInTransition(); + bool needsTransition() const; + void updateTransitions(timestamp now); + +public: + // loaded image dimensions + uint32_t width = 0, height = 0; + + // has been uploaded to texture + bool textured = false; + + // the uploaded texture + uint32_t texture = 0; + + // texture opacity + double opacity = 0; + +private: + mutable std::mutex mtx; + + // raw pixels have been loaded + bool loaded = false; + + // shared texture pool + std::shared_ptr texturepool; + + // min/mag filter + uint32_t filter = 0; + + // the raw pixels + std::unique_ptr img; + + // fade in transition + std::shared_ptr fade_transition = nullptr; +}; + +} + +#endif diff --git a/include/mbgl/util/rect.hpp b/include/mbgl/util/rect.hpp new file mode 100644 index 0000000000..a216b8e145 --- /dev/null +++ b/include/mbgl/util/rect.hpp @@ -0,0 +1,21 @@ +#ifndef MBGL_UTIL_RECT +#define MBGL_UTIL_RECT + +namespace mbgl { + +template +struct Rect { + explicit Rect(T x, T y, T w, T h) : x(x), y(y), w(w), h(h) {} + T x = 0, y = 0; + T w = 0, h = 0; + + template + Rect operator *(Number value) const { + return Rect(x * value, y * value, w * value, h * value); + } + + operator bool() const { return w == 0 || h == 0; } +}; +} + +#endif diff --git a/include/mbgl/util/recursive_wrapper.hpp b/include/mbgl/util/recursive_wrapper.hpp new file mode 100644 index 0000000000..a616805c0f --- /dev/null +++ b/include/mbgl/util/recursive_wrapper.hpp @@ -0,0 +1,127 @@ +#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP + +#include + +namespace mbgl { namespace util { + +template +class recursive_wrapper +{ +public: + using type = T; +private: + + T* p_; + +public: + + ~recursive_wrapper(); + recursive_wrapper(); + + recursive_wrapper(recursive_wrapper const& operand); + recursive_wrapper(T const& operand); + recursive_wrapper(recursive_wrapper&& operand); + recursive_wrapper(T&& operand); + +private: + + void assign(const T& rhs); + +public: + + inline recursive_wrapper& operator=(recursive_wrapper const& rhs) + { + assign( rhs.get() ); + return *this; + } + + inline recursive_wrapper& operator=(T const& rhs) + { + assign( rhs ); + return *this; + } + + inline void swap(recursive_wrapper& operand) noexcept + { + T* temp = operand.p_; + operand.p_ = p_; + p_ = temp; + } + + + recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept + { + swap(rhs); + return *this; + } + + recursive_wrapper& operator=(T&& rhs) + { + get() = std::move(rhs); + return *this; + } + + +public: + + T& get() { return *get_pointer(); } + const T& get() const { return *get_pointer(); } + T* get_pointer() { return p_; } + const T* get_pointer() const { return p_; } + operator T const&() const { return this->get(); } + operator T&() { return this->get(); } +}; + +template +recursive_wrapper::~recursive_wrapper() +{ + delete p_; +} + +template +recursive_wrapper::recursive_wrapper() + : p_(new T) +{ +} + +template +recursive_wrapper::recursive_wrapper(recursive_wrapper const& operand) + : p_(new T( operand.get() )) +{ +} + +template +recursive_wrapper::recursive_wrapper(T const& operand) + : p_(new T(operand)) +{ +} + +template +recursive_wrapper::recursive_wrapper(recursive_wrapper&& operand) + : p_(operand.p_) +{ + operand.p_ = nullptr; +} + +template +recursive_wrapper::recursive_wrapper(T&& operand) + : p_(new T( std::move(operand) )) +{ +} + +template +void recursive_wrapper::assign(const T& rhs) +{ + this->get() = rhs; +} + +template +inline void swap(recursive_wrapper& lhs, recursive_wrapper& rhs) noexcept +{ + lhs.swap(rhs); +} + +}} + +#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP diff --git a/include/mbgl/util/std.hpp b/include/mbgl/util/std.hpp new file mode 100644 index 0000000000..051f89bb60 --- /dev/null +++ b/include/mbgl/util/std.hpp @@ -0,0 +1,38 @@ +#ifndef MBGL_UTIL_STD +#define MBGL_UTIL_STD + +#include + +namespace std { + +// C++14 backfill from http://herbsutter.com/gotw/_102/ +template +::std::unique_ptr make_unique(Args&& ...args) { + return ::std::unique_ptr(new T(::std::forward(args)...)); +} + +} + +namespace mbgl { +namespace util { + +template +void erase_if(Container &container, ForwardIterator it, const ForwardIterator end, Predicate pred) { + while (it != end) { + if (pred(*it)) { + container.erase(it++); + } else { + ++it; + } + } +} + +template +void erase_if(Container &container, Predicate pred) { + erase_if(container, container.begin(), container.end(), pred); +} + +} +} + +#endif diff --git a/include/mbgl/util/string.hpp b/include/mbgl/util/string.hpp new file mode 100644 index 0000000000..f17d55cec3 --- /dev/null +++ b/include/mbgl/util/string.hpp @@ -0,0 +1,24 @@ +#ifndef MBGL_UTIL_STRING +#define MBGL_UTIL_STRING + +#include + +namespace mbgl { +namespace util { + +template +inline std::string sprintf(const char *msg, Args... args) { + char res[max]; + int len = snprintf(res, sizeof(res), msg, args...); + return std::string(res, len); +} + +template +inline std::string sprintf(const std::string &msg, Args... args) { + return sprintf(msg.c_str(), args...); +} + +} +} + +#endif diff --git a/include/mbgl/util/texturepool.hpp b/include/mbgl/util/texturepool.hpp new file mode 100644 index 0000000000..566d8c1750 --- /dev/null +++ b/include/mbgl/util/texturepool.hpp @@ -0,0 +1,25 @@ +#ifndef MBGL_UTIL_TEXTUREPOOL +#define MBGL_UTIL_TEXTUREPOOL + +#include +#include + +#include +#include + +namespace mbgl { + +class Texturepool : private util::noncopyable { + +public: + GLuint getTextureID(); + void removeTextureID(GLuint texture_id); + void clearTextureIDs(); + +private: + std::set texture_ids; +}; + +} + +#endif diff --git a/include/mbgl/util/threadpool.hpp b/include/mbgl/util/threadpool.hpp new file mode 100644 index 0000000000..497d4e3083 --- /dev/null +++ b/include/mbgl/util/threadpool.hpp @@ -0,0 +1,45 @@ +#ifndef MBGL_UTIL_THREADPOOL +#define MBGL_UTIL_THREADPOOL + +#include +#include +#include + +namespace mbgl { +namespace util { + +class Threadpool { +private: + class Worker { + public: + Worker(Threadpool& pool); + ~Worker(); + static void *loop(void *ptr); + + private: + Threadpool& pool; + pthread_t thread; + }; + +public: + Threadpool(int max_workers = 4); + typedef void (*Callback)(void *); + void add(Callback callback, void *data); + +private: + typedef std::pair Task; + const int max_workers; + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t condition = PTHREAD_COND_INITIALIZER; + std::forward_list workers; + int worker_count = 0; + std::queue tasks; +}; + +extern std::unique_ptr threadpool; + +} +} + +#endif + diff --git a/include/mbgl/util/time.hpp b/include/mbgl/util/time.hpp new file mode 100644 index 0000000000..eacee2c982 --- /dev/null +++ b/include/mbgl/util/time.hpp @@ -0,0 +1,42 @@ +#ifndef MBGL_UTIL_TIME +#define MBGL_UTIL_TIME + +#include + +namespace mbgl { + +typedef uint64_t timestamp; + +namespace util { + + +// Returns time in nanoseconds since an arbitrary point in the past. This has +// no relation to the current time, but is continuously increasing, so +// comparisons between different timestamps produce meaningful values. +inline timestamp now() { + return uv_hrtime(); +} +} + +// used for time conversions +constexpr timestamp operator"" _nanoseconds (long double ns) { return ns; } +constexpr timestamp operator"" _nanosecond (long double ns) { return ns; } +constexpr timestamp operator"" _microseconds (long double us) { return us * 1e3; } +constexpr timestamp operator"" _microsecond (long double us) { return us * 1e3; } +constexpr timestamp operator"" _milliseconds (long double ms) { return ms * 1e6; } +constexpr timestamp operator"" _millisecond (long double ms) { return ms * 1e6; } +constexpr timestamp operator"" _seconds (long double s) { return s * 1e9; } +constexpr timestamp operator"" _second (long double s) { return s * 1e9; } + +constexpr timestamp operator"" _nanoseconds (unsigned long long ns) { return ns; } +constexpr timestamp operator"" _nanosecond (unsigned long long ns) { return ns; } +constexpr timestamp operator"" _microseconds (unsigned long long us) { return us * 1e3; } +constexpr timestamp operator"" _microsecond (unsigned long long us) { return us * 1e3; } +constexpr timestamp operator"" _milliseconds (unsigned long long ms) { return ms * 1e6; } +constexpr timestamp operator"" _millisecond (unsigned long long ms) { return ms * 1e6; } +constexpr timestamp operator"" _seconds (unsigned long long s) { return s * 1e9; } +constexpr timestamp operator"" _second (unsigned long long s) { return s * 1e9; } + +} + +#endif diff --git a/include/mbgl/util/timer.hpp b/include/mbgl/util/timer.hpp new file mode 100644 index 0000000000..8171c2f5d1 --- /dev/null +++ b/include/mbgl/util/timer.hpp @@ -0,0 +1,40 @@ +#ifndef MBGL_UTIL_TIMER +#define MBGL_UTIL_TIMER + +#include + +#include + +namespace mbgl { +namespace util { + +#ifndef DISABLE_TIMER +class timer { +public: + timer(Event event = Event::General); + timer(EventSeverity severity, Event event = Event::General); + timer(const std::string &name, Event event = Event::General); + timer(const std::string &name, EventSeverity severity, Event event = Event::General); + void report(const std::string &name); + ~timer(); + +private: + const std::string name; + EventSeverity severity = EventSeverity::Debug; + Event event = Event::General; + uint64_t start; +}; +#else +class timer { + inline timer(Event event = Event::General); + inline timer(EventSeverity severity, Event event = Event::General); + inline timer(const std::string &name, Event event = Event::General); + inline timer(const std::string &name, EventSeverity severity, Event event = Event::General); + inline void report(const std::string &name) {} + inline ~timer() {} +}; +#endif +} +} + +#endif diff --git a/include/mbgl/util/token.hpp b/include/mbgl/util/token.hpp new file mode 100644 index 0000000000..a794e0489c --- /dev/null +++ b/include/mbgl/util/token.hpp @@ -0,0 +1,52 @@ +#ifndef MBGL_UTIL_TOKEN +#define MBGL_UTIL_TOKEN + +#ifdef __linux__ +#include +namespace regex_impl = boost; +#else +#include +namespace regex_impl = std; +#endif + +#include + +namespace mbgl { +namespace util { + +namespace detail { +const regex_impl::regex tokenRegex("\\{(\\w+)\\}"); +const regex_impl::sregex_token_iterator tokensEnd = regex_impl::sregex_token_iterator(); +} + +template +std::string replaceTokens(const std::string &source, const Lookup &lookup) { + std::string result; + result.reserve(source.size()); + + bool token = false; + for (auto token_it = regex_impl::sregex_token_iterator(source.begin(), source.end(), + detail::tokenRegex, {-1, 1}); + token_it != detail::tokensEnd; ++token_it, token = !token) { + if (!token_it->matched) { + continue; + } + + result += token ? lookup(token_it->str()) : token_it->str(); + } + + return result; +} + +template +inline std::string replaceTokens(const std::string &source, const std::map &properties) { + return replaceTokens(source, [&properties](const std::string &token) -> std::string { + const auto it_prop = properties.find(token); + return it_prop != properties.end() ? toString(it_prop->second) : ""; + }); +} + +} // end namespace util +} // end namespace mbgl + +#endif diff --git a/include/mbgl/util/transition.hpp b/include/mbgl/util/transition.hpp new file mode 100644 index 0000000000..b12527124e --- /dev/null +++ b/include/mbgl/util/transition.hpp @@ -0,0 +1,84 @@ +#ifndef MBGL_UTIL_TRANSITION +#define MBGL_UTIL_TRANSITION + +#include +#include +#include + +namespace mbgl { +namespace util { + +class transition : private noncopyable { +public: + enum state { + running, + complete + }; + + inline transition(timestamp start, timestamp duration) + : start(start), + duration(duration) {} + + inline float progress(timestamp now) const { + if (duration == 0) return 1; + if (start > now) return 0; + + return (float)(now - start) / duration; + } + + virtual state update(timestamp now) const = 0; + virtual ~transition(); + +protected: + double interpolateDouble(double from, double to, double t) const; + float interpolateFloat(float from, float to, double t) const; + Color interpolateColor(Color from, Color to, double t) const; + std::array interpolateFloatArray(std::array from, std::array to, double t) const; + +protected: + const timestamp start, duration; +}; + +template +class ease_transition : public transition { +public: + ease_transition(T from, T to, T& value, timestamp start, timestamp duration) + : transition(start, duration), + from(from), + to(to), + value(value) {} + + state update(timestamp now) const; + +private: + const T from, to; + T& value; + +}; + +template +class timeout : public transition { +public: + timeout(T final_value, T& value, timestamp start, timestamp duration) + : transition(start, duration), + final_value(final_value), + value(value) {} + + state update(timestamp now) const { + if (progress(now) >= 1) { + value = final_value; + return complete; + } else { + return running; + } + } + +private: + const T final_value; + T& value; +}; + +} +} + +#endif diff --git a/include/mbgl/util/unitbezier.hpp b/include/mbgl/util/unitbezier.hpp new file mode 100644 index 0000000000..095e15f809 --- /dev/null +++ b/include/mbgl/util/unitbezier.hpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MBGL_UTIL_UNITBEZIER +#define MBGL_UTIL_UNITBEZIER + +#include + +namespace mbgl { +namespace util { + +struct UnitBezier { + UnitBezier(double p1x, double p1y, double p2x, double p2y) { + // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). + cx = 3.0 * p1x; + bx = 3.0 * (p2x - p1x) - cx; + ax = 1.0 - cx - bx; + + cy = 3.0 * p1y; + by = 3.0 * (p2y - p1y) - cy; + ay = 1.0 - cy - by; + } + + double sampleCurveX(double t) { + // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. + return ((ax * t + bx) * t + cx) * t; + } + + double sampleCurveY(double t) { + return ((ay * t + by) * t + cy) * t; + } + + double sampleCurveDerivativeX(double t) { + return (3.0 * ax * t + 2.0 * bx) * t + cx; + } + + // Given an x value, find a parametric value it came from. + double solveCurveX(double x, double epsilon) { + double t0; + double t1; + double t2; + double x2; + double d2; + int i; + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 8; ++i) { + x2 = sampleCurveX(t2) - x; + if (fabs (x2) < epsilon) + return t2; + d2 = sampleCurveDerivativeX(t2); + if (fabs(d2) < 1e-6) + break; + t2 = t2 - x2 / d2; + } + + // Fall back to the bisection method for reliability. + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) + return t0; + if (t2 > t1) + return t1; + + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (fabs(x2 - x) < epsilon) + return t2; + if (x > x2) + t0 = t2; + else + t1 = t2; + t2 = (t1 - t0) * .5 + t0; + } + + // Failure. + return t2; + } + + double solve(double x, double epsilon) { + return sampleCurveY(solveCurveX(x, epsilon)); + } + +private: + double ax; + double bx; + double cx; + + double ay; + double by; + double cy; +}; + +} +} + +#endif diff --git a/include/mbgl/util/utf.hpp b/include/mbgl/util/utf.hpp new file mode 100644 index 0000000000..5dfc4ad2d1 --- /dev/null +++ b/include/mbgl/util/utf.hpp @@ -0,0 +1,50 @@ +#ifndef MBGL_UTIL_UTF +#define MBGL_UTIL_UTF + +#include + +// g++/libstdc++ is missing c++11 codecvt support +#ifdef __linux__ +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif +#include +#pragma GCC diagnostic pop +#else +#include +#include +#endif + +namespace mbgl { + +namespace util { + +#ifdef __linux__ + +class utf8_to_utf32 { + public: + explicit utf8_to_utf32() {} + std::u32string convert(std::string const& utf8) { + return boost::locale::conv::utf_to_utf(utf8); + } +}; + +#else + +class utf8_to_utf32 { + public: + explicit utf8_to_utf32() + : utf32conv_() {} + std::u32string convert(std::string const& utf8) { + return utf32conv_.from_bytes(utf8); + } + private: + std::wstring_convert, char32_t> utf32conv_; +}; + +#endif + +}} + +#endif diff --git a/include/mbgl/util/uv.hpp b/include/mbgl/util/uv.hpp new file mode 100644 index 0000000000..f36da83e4d --- /dev/null +++ b/include/mbgl/util/uv.hpp @@ -0,0 +1,141 @@ +#ifndef MBGL_UTIL_UV +#define MBGL_UTIL_UV + +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif + +#include + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +namespace uv { + +class loop { +public: + inline loop() : l(uv_loop_new()) {} + inline ~loop() { uv_loop_delete(l); } + + inline uv_loop_t *operator*() { return l; } + +private: + uv_loop_t *l; +}; + +class mutex { +public: + inline mutex() { + if (uv_mutex_init(&mtx) != 0) { + throw std::runtime_error("failed to initialize mutex"); + } + } + inline ~mutex() { uv_mutex_destroy(&mtx); } + inline void lock() { uv_mutex_lock(&mtx); } + inline void unlock() { uv_mutex_unlock(&mtx); } + +private: + uv_mutex_t mtx; +}; + +class lock { +public: + lock(mutex &mtx) : mtx(mtx) { mtx.lock(); } + ~lock() { mtx.unlock(); } + +private: + mutex &mtx; +}; + +class rwlock { +public: + inline rwlock() { + if (uv_rwlock_init(&mtx) != 0) { + throw std::runtime_error("failed to initialize read-write lock"); + } + } + inline ~rwlock() { uv_rwlock_destroy(&mtx); } + inline void rdlock() { uv_rwlock_rdlock(&mtx); } + inline void wrlock() { uv_rwlock_wrlock(&mtx); } + inline void rdunlock() { uv_rwlock_rdunlock(&mtx); } + inline void wrunlock() { uv_rwlock_wrunlock(&mtx); } + +private: + uv_rwlock_t mtx; +}; + +class readlock { +public: + inline readlock(rwlock &mtx) : mtx(mtx) { mtx.rdlock(); } + inline ~readlock() { mtx.rdunlock(); } + +private: + rwlock &mtx; +}; + +class writelock { +public: + inline writelock(rwlock &mtx) : mtx(mtx) { mtx.wrlock(); } + inline ~writelock() { mtx.wrunlock(); } + +private: + rwlock &mtx; +}; + +class once { +public: + typedef void (*callback)(); + void operator()(void (*callback)(void)) { + uv_once(&o, callback); + } + +private: + uv_once_t o = UV_ONCE_INIT; +}; + +template +class work { +public: + typedef void (*work_callback)(T &object); + typedef void (*after_work_callback)(T &object); + + template + work(const std::shared_ptr &loop, work_callback work_cb, after_work_callback after_work_cb, Args&&... args) + : loop(loop), + data(std::forward(args)...), + work_cb(work_cb), + after_work_cb(after_work_cb) { + req.data = this; + uv_queue_work(**loop, &req, do_work, after_work); + } + +private: + static void do_work(uv_work_t *req) { + work *w = static_cast *>(req->data); + w->work_cb(w->data); + } + + static void after_work(uv_work_t *req, int) { + work *w = static_cast *>(req->data); + w->after_work_cb(w->data); + delete w; + } + +private: + std::shared_ptr loop; + uv_work_t req; + T data; + work_callback work_cb; + after_work_callback after_work_cb; +}; + +} + +#endif diff --git a/include/mbgl/util/variant.hpp b/include/mbgl/util/variant.hpp new file mode 100644 index 0000000000..ddc82ee311 --- /dev/null +++ b/include/mbgl/util/variant.hpp @@ -0,0 +1,731 @@ +#ifndef MAPBOX_UTIL_VARIANT_HPP +#define MAPBOX_UTIL_VARIANT_HPP + +#include +#include +#include +#include // std::move/swap +#include // runtime_error +#include // operator new +#include // size_t +#include +#include + +#include "recursive_wrapper.hpp" + +#ifdef _MSC_VER + // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx + #ifdef NDEBUG + #define VARIANT_INLINE __forceinline + #else + #define VARIANT_INLINE __declspec(noinline) + #endif +#else + #ifdef NDEBUG + #define VARIANT_INLINE inline __attribute__((always_inline)) + #else + #define VARIANT_INLINE __attribute__((noinline)) + #endif +#endif + +#define VARIANT_MAJOR_VERSION 0 +#define VARIANT_MINOR_VERSION 1 +#define VARIANT_PATCH_VERSION 0 + +// translates to 100 +#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) + +namespace mbgl { namespace util { namespace detail { + +static constexpr std::size_t invalid_value = std::size_t(-1); + +template +struct direct_type; + +template +struct direct_type +{ + static constexpr std::size_t index = std::is_same::value + ? sizeof...(Types) : direct_type::index; +}; + +template +struct direct_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct convertible_type; + +template +struct convertible_type +{ + static constexpr std::size_t index = std::is_convertible::value + ? sizeof...(Types) : convertible_type::index; +}; + +template +struct convertible_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct value_traits +{ + static constexpr std::size_t direct_index = direct_type::index; + static constexpr std::size_t index = + (direct_index == invalid_value) ? convertible_type::index : direct_index; +}; + +template +struct is_valid_type; + +template +struct is_valid_type +{ + static constexpr bool value = std::is_convertible::value + || is_valid_type::value; +}; + +template +struct is_valid_type : std::false_type {}; + +template +struct select_type +{ + static_assert(N < sizeof...(Types), "index out of bounds"); +}; + +template +struct select_type +{ + using type = typename select_type::type; +}; + +template +struct select_type<0, T, Types...> +{ + using type = T; +}; + +} // namespace detail + +// static visitor +template +struct static_visitor +{ + using result_type = R; +protected: + static_visitor() {} + ~static_visitor() {} +}; + + +template +struct static_max; + +template +struct static_max +{ + static const std::size_t value = arg; +}; + +template +struct static_max +{ + static const std::size_t value = arg1 >= arg2 ? static_max::value : + static_max::value; +}; + +template +struct variant_helper; + +template +struct variant_helper +{ + VARIANT_INLINE static void destroy(const std::size_t id, void * data) + { + if (id == sizeof...(Types)) + { + reinterpret_cast(data)->~T(); + } + else + { + variant_helper::destroy(id, data); + } + } + + VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value) + { + if (old_id == sizeof...(Types)) + { + new (new_value) T(std::move(*reinterpret_cast(old_value))); + //std::memcpy(new_value, old_value, sizeof(T)); + // ^^ DANGER: this should only be considered for relocatable types e.g built-in types + // Also, I don't see any measurable performance benefit just yet + } + else + { + variant_helper::move(old_id, old_value, new_value); + } + } + + VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value) + { + if (old_id == sizeof...(Types)) + { + new (new_value) T(*reinterpret_cast(old_value)); + } + else + { + variant_helper::copy(old_id, old_value, new_value); + } + } +}; + +template<> struct variant_helper<> +{ + VARIANT_INLINE static void destroy(const std::size_t, void *) {} + VARIANT_INLINE static void move(const std::size_t, void *, void *) {} + VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {} +}; + +namespace detail { + +template +struct unwrapper +{ + T const& operator() (T const& obj) const + { + return obj; + } + + T& operator() (T & obj) const + { + return obj; + } +}; + + +template +struct unwrapper> +{ + auto operator() (recursive_wrapper const& obj) const + -> typename recursive_wrapper::type const& + { + return obj.get(); + } +}; + + +template +struct dispatcher; + +template +struct dispatcher +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v, F f) + { + if (v.get_type_index() == sizeof...(Types)) + { + return f(unwrapper()(v. template get())); + } + else + { + return dispatcher::apply_const(v, f); + } + } + + VARIANT_INLINE static result_type apply(V & v, F f) + { + if (v.get_type_index() == sizeof...(Types)) + { + return f(unwrapper()(v. template get())); + } + else + { + return dispatcher::apply(v, f); + } + } +}; + +template +struct dispatcher +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, F) + { + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); + } + + VARIANT_INLINE static result_type apply(V &, F) + { + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); + } +}; + + +template +struct binary_dispatcher_rhs; + +template +struct binary_dispatcher_rhs +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) + { + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); + } + else + { + return binary_dispatcher_rhs::apply_const(lhs, rhs, f); + } + } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); + } + else + { + return binary_dispatcher_rhs::apply(lhs, rhs, f); + } + } + +}; + +template +struct binary_dispatcher_rhs +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + VARIANT_INLINE static result_type apply(V &, V &, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } +}; + + +template +struct binary_dispatcher_lhs; + +template +struct binary_dispatcher_lhs +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) + { + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(lhs. template get(), rhs. template get()); + } + else + { + return binary_dispatcher_lhs::apply_const(lhs, rhs, f); + } + } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(lhs. template get(), rhs. template get()); + } + else + { + return binary_dispatcher_lhs::apply(lhs, rhs, f); + } + } + +}; + +template +struct binary_dispatcher_lhs +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + + VARIANT_INLINE static result_type apply(V &, V &, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } +}; + +template +struct binary_dispatcher; + +template +struct binary_dispatcher +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) + { + if (v0.get_type_index() == sizeof...(Types)) + { + if (v0.get_type_index() == v1.get_type_index()) + { + return f(v0. template get(), v1. template get()); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply_const(v0, v1, f); + } + } + else if (v1.get_type_index() == sizeof...(Types)) + { + return binary_dispatcher_lhs::apply_const(v0, v1, f); + } + return binary_dispatcher::apply_const(v0, v1, f); + } + + VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) + { + if (v0.get_type_index() == sizeof...(Types)) + { + if (v0.get_type_index() == v1.get_type_index()) + { + return f(v0. template get(), v1. template get()); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply(v0, v1, f); + } + } + else if (v1.get_type_index() == sizeof...(Types)) + { + return binary_dispatcher_lhs::apply(v0, v1, f); + } + return binary_dispatcher::apply(v0, v1, f); + } +}; + +template +struct binary_dispatcher +{ + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + + VARIANT_INLINE static result_type apply(V &, V &, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } +}; + +// comparator functors +struct equal_comp +{ + template + bool operator()(T const& lhs, T const& rhs) const + { + return lhs == rhs; + } +}; + +struct less_comp +{ + template + bool operator()(T const& lhs, T const& rhs) const + { + return lhs < rhs; + } +}; + +template +class comparer : public static_visitor +{ +public: + explicit comparer(Variant const& lhs) noexcept + : lhs_(lhs) {} + comparer& operator=(comparer const&) = delete; + // visitor + template + bool operator()(T const& rhs_content) const + { + T const& lhs_content = lhs_.template get(); + return Comp()(lhs_content, rhs_content); + } +private: + Variant const& lhs_; +}; + +// operator<< helper +template +class printer : public static_visitor<> +{ +public: + explicit printer(Out & out) + : out_(out) {} + printer& operator=(printer const&) = delete; + +// visitor + template + void operator()(T const& operand) const + { + out_ << operand; + } +private: + Out & out_; +}; + +} // namespace detail + +template +class variant +{ +private: + + static const std::size_t data_size = static_max::value; + static const std::size_t data_align = static_max::value; + + using data_type = typename std::aligned_storage::type; + using helper_type = variant_helper; + + std::size_t type_index; + data_type data; + +public: + + VARIANT_INLINE variant() + : type_index(sizeof...(Types) - 1) + { + new (&data) typename detail::select_type<0, Types...>::type(); + } + + template ::value>::type> + VARIANT_INLINE explicit variant(T const& val) noexcept + : type_index(detail::value_traits::index) + { + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(val); + } + + template ::value>::type> + VARIANT_INLINE variant(T && val) noexcept + : type_index(detail::value_traits::index) + { + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(std::forward(val)); // nothrow + } + + VARIANT_INLINE variant(variant const& old) + : type_index(old.type_index) + { + helper_type::copy(old.type_index, &old.data, &data); + } + + VARIANT_INLINE variant(variant&& old) noexcept + : type_index(old.type_index) + { + helper_type::move(old.type_index, &old.data, &data); + } + + friend void swap(variant & first, variant & second) + { + using std::swap; //enable ADL + swap(first.type_index, second.type_index); + swap(first.data, second.data); + } + + VARIANT_INLINE variant& operator=(variant other) + { + swap(*this, other); + return *this; + } + + // conversions + // move-assign + template + VARIANT_INLINE variant& operator=(T && rhs) noexcept + { + variant temp(std::move(rhs)); + swap(*this, temp); + return *this; + } + + // copy-assign + template + VARIANT_INLINE variant& operator=(T const& rhs) + { + variant temp(rhs); + swap(*this, temp); + return *this; + } + + template + VARIANT_INLINE bool is() const + { + return (type_index == detail::direct_type::index); + } + + VARIANT_INLINE bool valid() const + { + return (type_index != detail::invalid_value); + } + + template + VARIANT_INLINE void set(Args&&... args) + { + helper_type::destroy(type_index, &data); + new (&data) T(std::forward(args)...); + type_index = detail::direct_type::index; + } + + template + VARIANT_INLINE T& get() + { + if (type_index == detail::direct_type::index) + { + return *reinterpret_cast(&data); + } + else + { + throw std::runtime_error("in get()"); + } + } + + template + VARIANT_INLINE T const& get() const + { + if (type_index == detail::direct_type::index) + { + return *reinterpret_cast(&data); + } + else + { + throw std::runtime_error("in get()"); + } + } + + VARIANT_INLINE std::size_t get_type_index() const + { + return type_index; + } + + // visitor + // unary + template + auto VARIANT_INLINE + static visit(V const& v, F f) + -> decltype(detail::dispatcher::apply_const(v, f)) + { + return detail::dispatcher::apply_const(v, f); + } + // non-const + template + auto VARIANT_INLINE + static visit(V & v, F f) + -> decltype(detail::dispatcher::apply(v, f)) + { + return detail::dispatcher::apply(v, f); + } + + // binary + // const + template + auto VARIANT_INLINE + static binary_visit(V const& v0, V const& v1, F f) + -> decltype(detail::binary_dispatcher::apply_const(v0, v1, f)) + { + return detail::binary_dispatcher::apply_const(v0, v1, f); + } + // non-const + template + auto VARIANT_INLINE + static binary_visit(V& v0, V& v1, F f) + -> decltype(detail::binary_dispatcher::apply(v0, v1, f)) + { + return detail::binary_dispatcher::apply(v0, v1, f); + } + + ~variant() noexcept + { + helper_type::destroy(type_index, &data); + } + + // comparison operators + // equality + VARIANT_INLINE bool operator==(variant const& rhs) const + { + if (this->get_type_index() != rhs.get_type_index()) + return false; + detail::comparer visitor(*this); + return visit(rhs, visitor); + } + // less than + VARIANT_INLINE bool operator<(variant const& rhs) const + { + if (this->get_type_index() != rhs.get_type_index()) + { + return this->get_type_index() < rhs.get_type_index(); + // ^^ borrowed from boost::variant + } + detail::comparer visitor(*this); + return visit(rhs, visitor); + } +}; + +// unary visitor interface + +// const +template +auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) +{ + return V::visit(v, f); +} +// non-const +template +auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) +{ + return V::visit(v, f); +} + +// binary visitor interface +// const +template +auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) +{ + return V::binary_visit(v0, v1, f); +} +// non-const +template +auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) +{ + return V::binary_visit(v0, v1, f); +} + + +// operator<< +template +VARIANT_INLINE std::basic_ostream& +operator<< (std::basic_ostream& out, Variant const& rhs) +{ + detail::printer> visitor(out); + apply_visitor(visitor, rhs); + return out; +} + +}} + +#endif // MAPBOX_UTIL_VARIANT_HPP diff --git a/include/mbgl/util/vec.hpp b/include/mbgl/util/vec.hpp new file mode 100644 index 0000000000..0b9bf63d53 --- /dev/null +++ b/include/mbgl/util/vec.hpp @@ -0,0 +1,117 @@ +#ifndef MBGL_UTIL_VEC +#define MBGL_UTIL_VEC + +#include +#include +#include +#include +#include + +namespace mbgl { + +template +struct vec2 { + struct null {}; + typedef T Type; + + T x, y; + + inline vec2() {} + + template::has_quiet_NaN, int>::type = 0> + inline vec2(null) : x(std::numeric_limits::quiet_NaN()), y(std::numeric_limits::quiet_NaN()) {} + + template::has_quiet_NaN, int>::type = 0> + inline vec2(null) : x(std::numeric_limits::min()), y(std::numeric_limits::min()) {} + + inline vec2(const vec2& o) : x(o.x), y(o.y) {} + + template + inline vec2(const U& u) : x(u.x), y(u.y) {} + + inline vec2(T x, T y) : x(x), y(y) {} + + inline bool operator==(const vec2& rhs) const { + return x == rhs.x && y == rhs.y; + } + + template + inline typename std::enable_if::value, vec2>::type + operator*(O o) const { + return {x * o, y * o}; + } + + template + inline typename std::enable_if::value, vec2>::type & + operator*=(O o) { + x *= o; + y *= o; + } + + inline vec2 operator *(const std::array& matrix) { + return { x * matrix[0] + y * matrix[4] + matrix[12], x * matrix[1] + y * matrix[5] + matrix[13] }; + } + + template + inline typename std::enable_if::value, vec2>::type + operator-(O o) const { + return {x - o, y - o}; + } + + template + inline typename std::enable_if::value, vec2>::type + operator-(const O &o) const { + return {x - o.x, y - o.y}; + } + + template + inline vec2 matMul(const M &m) const { + return {m[0] * x + m[1] * y, m[2] * x + m[3] * y}; + } + + template::has_quiet_NaN, int>::type = 0> + inline operator bool() const { + return !isnan(x) && !isnan(y); + } + + template::has_quiet_NaN, int>::type = 0> + inline operator bool() const { + return x != std::numeric_limits::min() && y != std::numeric_limits::min(); + } +}; + +template +struct vec3 { + T x, y, z; + + inline vec3() {} + inline vec3(const vec3& o) : x(o.x), y(o.y), z(o.z) {} + inline vec3(T x, T y, T z) : x(x), y(y), z(z) {} + inline bool operator==(const vec3& rhs) const { + return x == rhs.x && y == rhs.y && z == rhs.z; + } +}; + +template +struct vec4 { + T x, y, z, w; + + inline vec4() {} + inline vec4(const vec4& o) : x(o.x), y(o.y), z(o.z), w(o.w) {} + inline vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {} + inline bool operator==(const vec4& rhs) const { + return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; + } +}; + + +struct box { + vec2 tl, tr, bl, br; + vec2 center; +}; + +typedef vec2 Coordinate; + +} + +#endif -- cgit v1.2.1