mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 21:21:17 +01:00
Drop the runtime to C++11
This is necessary in order for us to be able to run on more platforms. Diffs= 312a6c778 Drop the runtime to C++11
This commit is contained in:
@@ -1 +1 @@
|
||||
de4fe4d71a1eeef8e135991ca395c3159b42dc0d
|
||||
312a6c77883aaf469214e1dffc6953d4e82ace8c
|
||||
|
||||
@@ -40,7 +40,7 @@ project 'rive'
|
||||
do
|
||||
kind 'StaticLib'
|
||||
language 'C++'
|
||||
cppdialect 'C++17'
|
||||
cppdialect 'C++11'
|
||||
toolset 'clang'
|
||||
targetdir '%{cfg.system}/bin/%{cfg.buildcfg}'
|
||||
objdir '%{cfg.system}/obj/%{cfg.buildcfg}'
|
||||
|
||||
@@ -23,7 +23,7 @@ project('tests')
|
||||
do
|
||||
kind 'ConsoleApp'
|
||||
language 'C++'
|
||||
cppdialect 'C++17'
|
||||
cppdialect 'C++11'
|
||||
toolset (_OPTIONS["toolset"] or "clang")
|
||||
targetdir 'build/bin/%{cfg.buildcfg}'
|
||||
objdir 'build/obj/%{cfg.buildcfg}'
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rive/rive_types.hpp"
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string.h>
|
||||
|
||||
namespace rive
|
||||
@@ -17,13 +18,13 @@ namespace math
|
||||
constexpr float PI = 3.14159265f;
|
||||
constexpr float EPSILON = 1.f / (1 << 12); // Common threshold for detecting values near zero.
|
||||
|
||||
[[maybe_unused]] inline bool nearly_zero(float a, float tolerance = EPSILON)
|
||||
RIVE_MAYBE_UNUSED inline bool nearly_zero(float a, float tolerance = EPSILON)
|
||||
{
|
||||
assert(tolerance >= 0);
|
||||
return fabsf(a) <= tolerance;
|
||||
}
|
||||
|
||||
[[maybe_unused]] inline bool nearly_equal(float a, float b, float tolerance = EPSILON)
|
||||
RIVE_MAYBE_UNUSED inline bool nearly_equal(float a, float b, float tolerance = EPSILON)
|
||||
{
|
||||
return nearly_zero(b - a, tolerance);
|
||||
}
|
||||
@@ -38,7 +39,7 @@ constexpr float EPSILON = 1.f / (1 << 12); // Common threshold for detecting val
|
||||
//
|
||||
// Reference:
|
||||
// https://stackoverflow.com/questions/42926763/the-behaviour-of-floating-point-division-by-zero
|
||||
[[maybe_unused]]
|
||||
RIVE_MAYBE_UNUSED
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
__attribute__((no_sanitize("float-divide-by-zero"), always_inline))
|
||||
#endif
|
||||
@@ -46,16 +47,16 @@ inline static float
|
||||
ieee_float_divide(float a, float b)
|
||||
{
|
||||
static_assert(std::numeric_limits<float>::is_iec559,
|
||||
"Conformant IEEE 754 behavior for NaN and Inf is required.");
|
||||
"conformant IEEE 754 behavior for NaN and Inf is required");
|
||||
return a / b;
|
||||
}
|
||||
|
||||
// Reinterprets the underlying bits of src as the given type.
|
||||
template <typename Dst, typename Src> Dst bit_cast(const Src& src)
|
||||
{
|
||||
static_assert(sizeof(Dst) == sizeof(Src));
|
||||
static_assert(sizeof(Dst) == sizeof(Src), "sizes of both types must match");
|
||||
Dst dst;
|
||||
memcpy(&dst, &src, sizeof(Dst));
|
||||
RIVE_INLINE_MEMCPY(&dst, &src, sizeof(Dst));
|
||||
return dst;
|
||||
}
|
||||
} // namespace math
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <cmath>
|
||||
#include <stdio.h>
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace rive
|
||||
@@ -108,7 +109,7 @@ public:
|
||||
|
||||
private:
|
||||
// How much should we advance pts after encountering this verb?
|
||||
constexpr static int PtsAdvanceAfterVerb(PathVerb verb)
|
||||
inline static int PtsAdvanceAfterVerb(PathVerb verb)
|
||||
{
|
||||
switch (verb)
|
||||
{
|
||||
@@ -123,14 +124,14 @@ public:
|
||||
case PathVerb::close:
|
||||
return 0;
|
||||
}
|
||||
RIVE_UNREACHABLE;
|
||||
RIVE_UNREACHABLE();
|
||||
}
|
||||
|
||||
// Where is p0 relative to our m_pts pointer? We find the start point of segments by
|
||||
// peeking backwards from the current point, which works as long as there is always a
|
||||
// PathVerb::move before any geometry. (injectImplicitMoveToIfNeeded() guarantees this
|
||||
// to be the case.)
|
||||
constexpr static int PtsBacksetForVerb(PathVerb verb)
|
||||
inline static int PtsBacksetForVerb(PathVerb verb)
|
||||
{
|
||||
switch (verb)
|
||||
{
|
||||
@@ -145,7 +146,7 @@ public:
|
||||
case PathVerb::close:
|
||||
return -1;
|
||||
}
|
||||
RIVE_UNREACHABLE;
|
||||
RIVE_UNREACHABLE();
|
||||
}
|
||||
|
||||
const PathVerb* m_verbs;
|
||||
@@ -158,8 +159,10 @@ public:
|
||||
{
|
||||
RawPath dst;
|
||||
// todo: dst.reserve(src.ptCount, src.verbCount);
|
||||
for (auto [verb, pts] : *this)
|
||||
for (auto iter : *this)
|
||||
{
|
||||
PathVerb verb = std::get<0>(iter);
|
||||
const Vec2D* pts = std::get<1>(iter);
|
||||
switch (verb)
|
||||
{
|
||||
case PathVerb::move:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#ifndef _RIVE_SIMD_HPP_
|
||||
#define _RIVE_SIMD_HPP_
|
||||
|
||||
#include "rive/rive_types.hpp"
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
@@ -35,13 +36,6 @@ static_assert(std::numeric_limits<float>::is_iec559,
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
|
||||
#define SIMD_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
|
||||
// Recommended in https://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
namespace rive
|
||||
{
|
||||
namespace simd
|
||||
@@ -55,21 +49,12 @@ using gvec = T __attribute__((ext_vector_type(N))) __attribute__((aligned(sizeof
|
||||
|
||||
#else
|
||||
|
||||
#define SIMD_ALWAYS_INLINE inline
|
||||
#define __has_builtin(x) 0
|
||||
|
||||
// gvec needs to be polyfilled with templates.
|
||||
#pragma message("performance: ext_vector_type not supported. Consider using clang.")
|
||||
#include "simd_gvec_polyfill.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_memcpy)
|
||||
#define SIMD_INLINE_MEMCPY __builtin_memcpy
|
||||
#else
|
||||
#define SIMD_INLINE_MEMCPY memcpy
|
||||
#endif
|
||||
|
||||
namespace rive
|
||||
{
|
||||
namespace simd
|
||||
@@ -81,7 +66,7 @@ namespace simd
|
||||
//
|
||||
|
||||
// Returns true if all elements in x are equal to 0.
|
||||
template <int N> SIMD_ALWAYS_INLINE bool any(gvec<int32_t, N> x)
|
||||
template <int N> RIVE_ALWAYS_INLINE bool any(gvec<int32_t, N> x)
|
||||
{
|
||||
#if __has_builtin(__builtin_reduce_or)
|
||||
return __builtin_reduce_or(x);
|
||||
@@ -98,7 +83,7 @@ template <int N> SIMD_ALWAYS_INLINE bool any(gvec<int32_t, N> x)
|
||||
}
|
||||
|
||||
// Returns true if all elements in x are equal to ~0.
|
||||
template <int N> SIMD_ALWAYS_INLINE bool all(gvec<int32_t, N> x)
|
||||
template <int N> RIVE_ALWAYS_INLINE bool all(gvec<int32_t, N> x)
|
||||
{
|
||||
#if __has_builtin(__builtin_reduce_and)
|
||||
return __builtin_reduce_and(x);
|
||||
@@ -112,7 +97,7 @@ template <int N> SIMD_ALWAYS_INLINE bool all(gvec<int32_t, N> x)
|
||||
template <typename T,
|
||||
int N,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
|
||||
SIMD_ALWAYS_INLINE gvec<int32_t, N> isnan(gvec<T, N> x)
|
||||
RIVE_ALWAYS_INLINE gvec<int32_t, N> isnan(gvec<T, N> x)
|
||||
{
|
||||
return ~(x == x);
|
||||
}
|
||||
@@ -127,7 +112,7 @@ constexpr gvec<int32_t, N> isnan(gvec<T, N>)
|
||||
|
||||
// Elementwise ternary expression: "_if ? _then : _else" for each component.
|
||||
template <typename T, int N>
|
||||
SIMD_ALWAYS_INLINE gvec<T, N> if_then_else(gvec<int32_t, N> _if, gvec<T, N> _then, gvec<T, N> _else)
|
||||
RIVE_ALWAYS_INLINE gvec<T, N> if_then_else(gvec<int32_t, N> _if, gvec<T, N> _then, gvec<T, N> _else)
|
||||
{
|
||||
#if defined(__clang_major__) && __clang_major__ >= 13
|
||||
// The '?:' operator supports a vector condition beginning in clang 13.
|
||||
@@ -143,7 +128,7 @@ SIMD_ALWAYS_INLINE gvec<T, N> if_then_else(gvec<int32_t, N> _if, gvec<T, N> _the
|
||||
|
||||
// Similar to std::min(), with a noteworthy difference:
|
||||
// If a[i] or b[i] is NaN and the other is not, returns whichever is _not_ NaN.
|
||||
template <typename T, int N> SIMD_ALWAYS_INLINE gvec<T, N> min(gvec<T, N> a, gvec<T, N> b)
|
||||
template <typename T, int N> RIVE_ALWAYS_INLINE gvec<T, N> min(gvec<T, N> a, gvec<T, N> b)
|
||||
{
|
||||
#if __has_builtin(__builtin_elementwise_min)
|
||||
return __builtin_elementwise_min(a, b);
|
||||
@@ -156,7 +141,7 @@ template <typename T, int N> SIMD_ALWAYS_INLINE gvec<T, N> min(gvec<T, N> a, gve
|
||||
|
||||
// Similar to std::max(), with a noteworthy difference:
|
||||
// If a[i] or b[i] is NaN and the other is not, returns whichever is _not_ NaN.
|
||||
template <typename T, int N> SIMD_ALWAYS_INLINE gvec<T, N> max(gvec<T, N> a, gvec<T, N> b)
|
||||
template <typename T, int N> RIVE_ALWAYS_INLINE gvec<T, N> max(gvec<T, N> a, gvec<T, N> b)
|
||||
{
|
||||
#if __has_builtin(__builtin_elementwise_max)
|
||||
return __builtin_elementwise_max(a, b);
|
||||
@@ -174,14 +159,14 @@ template <typename T, int N> SIMD_ALWAYS_INLINE gvec<T, N> max(gvec<T, N> a, gve
|
||||
// Ignores hi and/or lo if they are NaN.
|
||||
//
|
||||
template <typename T, int N>
|
||||
SIMD_ALWAYS_INLINE gvec<T, N> clamp(gvec<T, N> x, gvec<T, N> lo, gvec<T, N> hi)
|
||||
RIVE_ALWAYS_INLINE gvec<T, N> clamp(gvec<T, N> x, gvec<T, N> lo, gvec<T, N> hi)
|
||||
{
|
||||
return min(max(lo, x), hi);
|
||||
}
|
||||
|
||||
// Returns the absolute value of x per element, with one exception:
|
||||
// If x[i] is an integer type and equal to the minimum representable value, returns x[i].
|
||||
template <typename T, int N> SIMD_ALWAYS_INLINE gvec<T, N> abs(gvec<T, N> x)
|
||||
template <typename T, int N> RIVE_ALWAYS_INLINE gvec<T, N> abs(gvec<T, N> x)
|
||||
{
|
||||
#if __has_builtin(__builtin_elementwise_abs)
|
||||
return __builtin_elementwise_abs(x);
|
||||
@@ -193,7 +178,7 @@ template <typename T, int N> SIMD_ALWAYS_INLINE gvec<T, N> abs(gvec<T, N> x)
|
||||
|
||||
////// Floating Point Functions //////
|
||||
|
||||
template <int N> SIMD_ALWAYS_INLINE gvec<float, N> floor(gvec<float, N> x)
|
||||
template <int N> RIVE_ALWAYS_INLINE gvec<float, N> floor(gvec<float, N> x)
|
||||
{
|
||||
#if __has_builtin(__builtin_elementwise_floor)
|
||||
return __builtin_elementwise_floor(x);
|
||||
@@ -206,7 +191,7 @@ template <int N> SIMD_ALWAYS_INLINE gvec<float, N> floor(gvec<float, N> x)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <int N> SIMD_ALWAYS_INLINE gvec<float, N> ceil(gvec<float, N> x)
|
||||
template <int N> RIVE_ALWAYS_INLINE gvec<float, N> ceil(gvec<float, N> x)
|
||||
{
|
||||
#if __has_builtin(__builtin_elementwise_ceil)
|
||||
return __builtin_elementwise_ceil(x);
|
||||
@@ -219,7 +204,7 @@ template <int N> SIMD_ALWAYS_INLINE gvec<float, N> ceil(gvec<float, N> x)
|
||||
}
|
||||
|
||||
// IEEE compliant sqrt.
|
||||
template <int N> SIMD_ALWAYS_INLINE gvec<float, N> sqrt(gvec<float, N> x)
|
||||
template <int N> RIVE_ALWAYS_INLINE gvec<float, N> sqrt(gvec<float, N> x)
|
||||
{
|
||||
// There isn't an elementwise builtin for sqrt. We define architecture-specific specializations
|
||||
// of this function later.
|
||||
@@ -229,42 +214,42 @@ template <int N> SIMD_ALWAYS_INLINE gvec<float, N> sqrt(gvec<float, N> x)
|
||||
}
|
||||
|
||||
#ifdef __SSE__
|
||||
template <> SIMD_ALWAYS_INLINE gvec<float, 4> sqrt(gvec<float, 4> x)
|
||||
template <> RIVE_ALWAYS_INLINE gvec<float, 4> sqrt(gvec<float, 4> x)
|
||||
{
|
||||
__m128 _x;
|
||||
SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 4);
|
||||
RIVE_INLINE_MEMCPY(&_x, &x, sizeof(float) * 4);
|
||||
_x = _mm_sqrt_ps(_x);
|
||||
SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 4);
|
||||
RIVE_INLINE_MEMCPY(&x, &_x, sizeof(float) * 4);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <> SIMD_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
template <> RIVE_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
{
|
||||
__m128 _x;
|
||||
SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 2);
|
||||
RIVE_INLINE_MEMCPY(&_x, &x, sizeof(float) * 2);
|
||||
_x = _mm_sqrt_ps(_x);
|
||||
SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 2);
|
||||
RIVE_INLINE_MEMCPY(&x, &_x, sizeof(float) * 2);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_NEON__
|
||||
#ifdef __aarch64__
|
||||
template <> SIMD_ALWAYS_INLINE gvec<float, 4> sqrt(gvec<float, 4> x)
|
||||
template <> RIVE_ALWAYS_INLINE gvec<float, 4> sqrt(gvec<float, 4> x)
|
||||
{
|
||||
float32x4_t _x;
|
||||
SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 4);
|
||||
RIVE_INLINE_MEMCPY(&_x, &x, sizeof(float) * 4);
|
||||
_x = vsqrtq_f32(_x);
|
||||
SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 4);
|
||||
RIVE_INLINE_MEMCPY(&x, &_x, sizeof(float) * 4);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <> SIMD_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
template <> RIVE_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
{
|
||||
float32x2_t _x;
|
||||
SIMD_INLINE_MEMCPY(&_x, &x, sizeof(float) * 2);
|
||||
RIVE_INLINE_MEMCPY(&_x, &x, sizeof(float) * 2);
|
||||
_x = vsqrt_f32(_x);
|
||||
SIMD_INLINE_MEMCPY(&x, &_x, sizeof(float) * 2);
|
||||
RIVE_INLINE_MEMCPY(&x, &_x, sizeof(float) * 2);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
@@ -272,12 +257,12 @@ template <> SIMD_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
|
||||
// This will only be present when building with Emscripten and "-msimd128".
|
||||
#if __has_builtin(__builtin_wasm_sqrt_f32x4)
|
||||
template <> SIMD_ALWAYS_INLINE gvec<float, 4> sqrt(gvec<float, 4> x)
|
||||
template <> RIVE_ALWAYS_INLINE gvec<float, 4> sqrt(gvec<float, 4> x)
|
||||
{
|
||||
return __builtin_wasm_sqrt_f32x4(x);
|
||||
}
|
||||
|
||||
template <> SIMD_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
template <> RIVE_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
{
|
||||
gvec<float, 4> _x{x.x, x.y};
|
||||
_x = __builtin_wasm_sqrt_f32x4(_x);
|
||||
@@ -291,7 +276,7 @@ template <> SIMD_ALWAYS_INLINE gvec<float, 2> sqrt(gvec<float, 2> x)
|
||||
//
|
||||
// See: https://stackoverflow.com/a/36387954
|
||||
#define SIMD_FAST_ACOS_MAX_ERROR 0.0167552f // .96 degrees
|
||||
template <int N> SIMD_ALWAYS_INLINE gvec<float, N> fast_acos(gvec<float, N> x)
|
||||
template <int N> RIVE_ALWAYS_INLINE gvec<float, N> fast_acos(gvec<float, N> x)
|
||||
{
|
||||
constexpr static float a = -0.939115566365855f;
|
||||
constexpr static float b = 0.9217841528914573f;
|
||||
@@ -306,36 +291,36 @@ template <int N> SIMD_ALWAYS_INLINE gvec<float, N> fast_acos(gvec<float, N> x)
|
||||
|
||||
////// Loading and storing //////
|
||||
|
||||
template <typename T, int N> SIMD_ALWAYS_INLINE gvec<T, N> load(const void* ptr)
|
||||
template <typename T, int N> RIVE_ALWAYS_INLINE gvec<T, N> load(const void* ptr)
|
||||
{
|
||||
gvec<T, N> ret;
|
||||
SIMD_INLINE_MEMCPY(&ret, ptr, sizeof(T) * N);
|
||||
RIVE_INLINE_MEMCPY(&ret, ptr, sizeof(T) * N);
|
||||
return ret;
|
||||
}
|
||||
SIMD_ALWAYS_INLINE gvec<float, 2> load2f(const void* ptr) { return load<float, 2>(ptr); }
|
||||
SIMD_ALWAYS_INLINE gvec<float, 4> load4f(const void* ptr) { return load<float, 4>(ptr); }
|
||||
SIMD_ALWAYS_INLINE gvec<int32_t, 2> load2i(const void* ptr) { return load<int32_t, 2>(ptr); }
|
||||
SIMD_ALWAYS_INLINE gvec<int32_t, 4> load4i(const void* ptr) { return load<int32_t, 4>(ptr); }
|
||||
SIMD_ALWAYS_INLINE gvec<uint32_t, 2> load2ui(const void* ptr) { return load<uint32_t, 2>(ptr); }
|
||||
SIMD_ALWAYS_INLINE gvec<uint32_t, 4> load4ui(const void* ptr) { return load<uint32_t, 4>(ptr); }
|
||||
RIVE_ALWAYS_INLINE gvec<float, 2> load2f(const void* ptr) { return load<float, 2>(ptr); }
|
||||
RIVE_ALWAYS_INLINE gvec<float, 4> load4f(const void* ptr) { return load<float, 4>(ptr); }
|
||||
RIVE_ALWAYS_INLINE gvec<int32_t, 2> load2i(const void* ptr) { return load<int32_t, 2>(ptr); }
|
||||
RIVE_ALWAYS_INLINE gvec<int32_t, 4> load4i(const void* ptr) { return load<int32_t, 4>(ptr); }
|
||||
RIVE_ALWAYS_INLINE gvec<uint32_t, 2> load2ui(const void* ptr) { return load<uint32_t, 2>(ptr); }
|
||||
RIVE_ALWAYS_INLINE gvec<uint32_t, 4> load4ui(const void* ptr) { return load<uint32_t, 4>(ptr); }
|
||||
|
||||
template <typename T, int N> SIMD_ALWAYS_INLINE void store(void* dst, gvec<T, N> vec)
|
||||
template <typename T, int N> RIVE_ALWAYS_INLINE void store(void* dst, gvec<T, N> vec)
|
||||
{
|
||||
SIMD_INLINE_MEMCPY(dst, &vec, sizeof(T) * N);
|
||||
RIVE_INLINE_MEMCPY(dst, &vec, sizeof(T) * N);
|
||||
}
|
||||
|
||||
template <typename T, int M, int N>
|
||||
SIMD_ALWAYS_INLINE gvec<T, M + N> join(gvec<T, M> a, gvec<T, N> b)
|
||||
RIVE_ALWAYS_INLINE gvec<T, M + N> join(gvec<T, M> a, gvec<T, N> b)
|
||||
{
|
||||
T data[M + N];
|
||||
SIMD_INLINE_MEMCPY(data, &a, sizeof(T) * M);
|
||||
SIMD_INLINE_MEMCPY(data + M, &b, sizeof(T) * N);
|
||||
RIVE_INLINE_MEMCPY(data, &a, sizeof(T) * M);
|
||||
RIVE_INLINE_MEMCPY(data + M, &b, sizeof(T) * N);
|
||||
return load<T, M + N>(data);
|
||||
}
|
||||
|
||||
////// Basic linear algebra //////
|
||||
|
||||
template <typename T, int N> SIMD_ALWAYS_INLINE T dot(gvec<T, N> a, gvec<T, N> b)
|
||||
template <typename T, int N> RIVE_ALWAYS_INLINE T dot(gvec<T, N> a, gvec<T, N> b)
|
||||
{
|
||||
auto d = a * b;
|
||||
T s = d[0];
|
||||
@@ -346,20 +331,20 @@ template <typename T, int N> SIMD_ALWAYS_INLINE T dot(gvec<T, N> a, gvec<T, N> b
|
||||
|
||||
// We can use __builtin_reduce_add for integer types.
|
||||
#if __has_builtin(__builtin_reduce_add)
|
||||
template <int N> SIMD_ALWAYS_INLINE int32_t dot(gvec<int32_t, N> a, gvec<int32_t, N> b)
|
||||
template <int N> RIVE_ALWAYS_INLINE int32_t dot(gvec<int32_t, N> a, gvec<int32_t, N> b)
|
||||
{
|
||||
auto d = a * b;
|
||||
return __builtin_reduce_add(d);
|
||||
}
|
||||
|
||||
template <int N> SIMD_ALWAYS_INLINE uint32_t dot(gvec<uint32_t, N> a, gvec<uint32_t, N> b)
|
||||
template <int N> RIVE_ALWAYS_INLINE uint32_t dot(gvec<uint32_t, N> a, gvec<uint32_t, N> b)
|
||||
{
|
||||
auto d = a * b;
|
||||
return __builtin_reduce_add(d);
|
||||
}
|
||||
#endif
|
||||
|
||||
SIMD_ALWAYS_INLINE float cross(gvec<float, 2> a, gvec<float, 2> b)
|
||||
RIVE_ALWAYS_INLINE float cross(gvec<float, 2> a, gvec<float, 2> b)
|
||||
{
|
||||
auto c = a * b.yx;
|
||||
return c.x - c.y;
|
||||
@@ -373,7 +358,7 @@ SIMD_ALWAYS_INLINE float cross(gvec<float, 2> a, gvec<float, 2> b)
|
||||
// structure seems to get better precision for things like chopping cubics on exact cusp points than
|
||||
// "a*(1 - t) + b*t" (which would return exactly b when t == 1).
|
||||
template <int N>
|
||||
SIMD_ALWAYS_INLINE gvec<float, N> mix(gvec<float, N> a, gvec<float, N> b, gvec<float, N> t)
|
||||
RIVE_ALWAYS_INLINE gvec<float, N> mix(gvec<float, N> a, gvec<float, N> b, gvec<float, N> t)
|
||||
{
|
||||
assert(simd::all(0.f <= t && t < 1.f));
|
||||
return (b - a) * t + a;
|
||||
@@ -381,8 +366,7 @@ SIMD_ALWAYS_INLINE gvec<float, N> mix(gvec<float, N> a, gvec<float, N> b, gvec<f
|
||||
} // namespace simd
|
||||
} // namespace rive
|
||||
|
||||
#undef SIMD_ALWAYS_INLINE
|
||||
#undef SIMD_INLINE_MEMCPY
|
||||
#undef RIVE_INLINE_MEMCPY
|
||||
|
||||
namespace rive
|
||||
{
|
||||
|
||||
@@ -143,10 +143,9 @@ template <typename T, int N> struct gvec<T, N, 0> : public gvec_data<T, N>
|
||||
T& operator[](size_t i) { return gvec_data<T, N>::data[i]; }
|
||||
};
|
||||
|
||||
static_assert(sizeof(gvec<float, 1>) == 4);
|
||||
static_assert(sizeof(gvec<float, 2>) == 8);
|
||||
static_assert(sizeof(gvec<float, 3>) == 12);
|
||||
static_assert(sizeof(gvec<float, 4>) == 16);
|
||||
static_assert(sizeof(gvec<float, 1>) == 4, "gvec<1> is expected to be tightly packed");
|
||||
static_assert(sizeof(gvec<float, 2>) == 8, "gvec<2> is expected to be tightly packed");
|
||||
static_assert(sizeof(gvec<float, 4>) == 16, "gvec<4> is expected to be tightly packed");
|
||||
|
||||
#define DECL_UNARY_OP(_OP_) \
|
||||
template <typename T, int N, Swizzle Z> gvec<T, N> operator _OP_(gvec<T, N, Z> x) \
|
||||
|
||||
@@ -9,44 +9,45 @@
|
||||
#ifndef _RIVE_TYPES_HPP_
|
||||
#define _RIVE_TYPES_HPP_
|
||||
|
||||
// clang-format off
|
||||
#include <memory> // For unique_ptr.
|
||||
#include <string.h> // For memcpy.
|
||||
|
||||
#if defined(DEBUG) && defined(NDEBUG)
|
||||
#error "can't determine if we're debug or release"
|
||||
#error "can't determine if we're debug or release"
|
||||
#endif
|
||||
|
||||
#if !defined(DEBUG) && !defined(NDEBUG)
|
||||
// we have to make a decision what mode we're in
|
||||
// historically this has been to look for NDEBUG, and in its
|
||||
// absence assume we're DEBUG.
|
||||
#define DEBUG 1
|
||||
// fyi - Xcode seems to set DEBUG (or not), so the above guess
|
||||
// doesn't work for them - so our projects may need to explicitly
|
||||
// set NDEBUG in our 'release' builds.
|
||||
// we have to make a decision what mode we're in
|
||||
// historically this has been to look for NDEBUG, and in its
|
||||
// absence assume we're DEBUG.
|
||||
#define DEBUG 1
|
||||
// fyi - Xcode seems to set DEBUG (or not), so the above guess
|
||||
// doesn't work for them - so our projects may need to explicitly
|
||||
// set NDEBUG in our 'release' builds.
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#ifndef RELEASE
|
||||
#define RELEASE 1
|
||||
#endif
|
||||
#else // debug mode
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
#ifndef RELEASE
|
||||
#define RELEASE 1
|
||||
#endif
|
||||
#else // debug mode
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Some checks to guess what platform we're building for
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#define RIVE_BUILD_FOR_APPLE
|
||||
#include <TargetConditionals.h>
|
||||
#define RIVE_BUILD_FOR_APPLE
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define RIVE_BUILD_FOR_IOS
|
||||
#elif TARGET_OS_MAC
|
||||
#define RIVE_BUILD_FOR_OSX
|
||||
#endif
|
||||
#if TARGET_OS_IPHONE
|
||||
#define RIVE_BUILD_FOR_IOS
|
||||
#elif TARGET_OS_MAC
|
||||
#define RIVE_BUILD_FOR_OSX
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -60,14 +61,59 @@
|
||||
#include <type_traits>
|
||||
|
||||
// Annotations to assert unreachable control flow.
|
||||
#ifdef __GNUC__ // GCC 4.8+, Clang, Intel and others compatible with GCC (-std=c++0x or above)
|
||||
#define RIVE_UNREACHABLE __builtin_unreachable()
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RIVE_UNREACHABLE __builtin_unreachable
|
||||
#elif _MSC_VER
|
||||
#define RIVE_UNREACHABLE __assume(0)
|
||||
#define RIVE_UNREACHABLE() __assume(0)
|
||||
#else
|
||||
#define RIVE_UNREACHABLE do {} while(0)
|
||||
#define RIVE_UNREACHABLE() \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
#if __cplusplus >= 201703L
|
||||
#define RIVE_MAYBE_UNUSED [[maybe_unused]]
|
||||
#else
|
||||
#define RIVE_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#define RIVE_FALLTHROUGH [[fallthrough]]
|
||||
#elif defined(__clang__)
|
||||
#define RIVE_FALLTHROUGH [[clang::fallthrough]]
|
||||
#else
|
||||
#define RIVE_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RIVE_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#else
|
||||
#define RIVE_ALWAYS_INLINE inline
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
// Recommended in https://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
#else
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_memcpy)
|
||||
#define RIVE_INLINE_MEMCPY __builtin_memcpy
|
||||
#else
|
||||
#define RIVE_INLINE_MEMCPY memcpy
|
||||
#endif
|
||||
|
||||
// Backports of later stl functions.
|
||||
namespace rivestd
|
||||
{
|
||||
template <class T, class... Args> std::unique_ptr<T> make_unique(Args&&... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
} // namespace rivestd
|
||||
|
||||
#endif // rive_types
|
||||
|
||||
@@ -27,6 +27,41 @@ void resetCounters();
|
||||
} // namespace SimpleArrayTesting
|
||||
#endif
|
||||
|
||||
// Helper for constructing and destructing arrays of objects.
|
||||
template <typename T, bool IsPOD = std::is_pod<T>()> class SimpleArrayHelper
|
||||
{
|
||||
public:
|
||||
static_assert(!std::is_pod<T>(), "This helper is for non-POD types.");
|
||||
static void DefaultConstructArray(T* ptr, T* end)
|
||||
{
|
||||
for (; ptr < end; ++ptr)
|
||||
new (ptr) T();
|
||||
}
|
||||
static void CopyConstructArray(const T* first, const T* end, T* ptr)
|
||||
{
|
||||
for (; first < end; ++first, ++ptr)
|
||||
new (ptr) T(*first);
|
||||
}
|
||||
static void DestructArray(T* ptr, T* end)
|
||||
{
|
||||
for (; ptr < end; ++ptr)
|
||||
ptr->~T();
|
||||
}
|
||||
};
|
||||
|
||||
// Specialized helper for constructing and destructing arrays of POD objects.
|
||||
template <typename T> class SimpleArrayHelper<T, true>
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_pod<T>(), "This helper is only for POD types.");
|
||||
static void DefaultConstructArray(T* ptr, T* end) {}
|
||||
static void CopyConstructArray(const T* first, const T* end, T* ptr)
|
||||
{
|
||||
memcpy(ptr, first, reinterpret_cast<uintptr_t>(end) - reinterpret_cast<uintptr_t>(first));
|
||||
}
|
||||
static void DestructArray(T* ptr, T* end) {}
|
||||
};
|
||||
|
||||
/// Lightweight heap array meant to be used when knowing the exact memory layout
|
||||
/// of the simple array is necessary, like marshaling the data to Dart/C#/Wasm.
|
||||
/// Note that it intentionally doesn't have push/add/resize functionality as
|
||||
@@ -41,14 +76,7 @@ public:
|
||||
SimpleArray() : m_ptr(nullptr), m_size(0) {}
|
||||
SimpleArray(size_t size) : m_ptr(static_cast<T*>(malloc(size * sizeof(T)))), m_size(size)
|
||||
{
|
||||
if constexpr (!std::is_pod<T>())
|
||||
{
|
||||
for (T *element = m_ptr, *end = m_ptr + m_size; element < end; element++)
|
||||
{
|
||||
new (element) T();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleArrayHelper<T>::DefaultConstructArray(m_ptr, m_ptr + m_size);
|
||||
#ifdef TESTING
|
||||
SimpleArrayTesting::mallocCount++;
|
||||
#endif
|
||||
@@ -56,28 +84,18 @@ public:
|
||||
SimpleArray(const T* ptr, size_t size) : SimpleArray(size)
|
||||
{
|
||||
assert(ptr <= ptr + size);
|
||||
if constexpr (std::is_pod<T>())
|
||||
{
|
||||
memcpy(m_ptr, ptr, size * sizeof(T));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (T *element = m_ptr, *end = m_ptr + m_size; element < end; element++)
|
||||
{
|
||||
new (element) T(ptr++);
|
||||
}
|
||||
}
|
||||
SimpleArrayHelper<T>::CopyConstructArray(ptr, ptr + size, m_ptr);
|
||||
}
|
||||
|
||||
constexpr SimpleArray(const SimpleArray<T>& other) : SimpleArray(other.m_ptr, other.m_size) {}
|
||||
|
||||
constexpr SimpleArray(SimpleArray<T>&& other) : m_ptr(other.m_ptr), m_size(other.m_size)
|
||||
SimpleArray(SimpleArray<T>&& other) : m_ptr(other.m_ptr), m_size(other.m_size)
|
||||
{
|
||||
other.m_ptr = nullptr;
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
constexpr SimpleArray(SimpleArrayBuilder<T>&& other);
|
||||
SimpleArray(SimpleArrayBuilder<T>&& other);
|
||||
|
||||
SimpleArray<T>& operator=(const SimpleArray<T>& other) = delete;
|
||||
|
||||
@@ -93,30 +111,20 @@ public:
|
||||
SimpleArray<T>& operator=(SimpleArrayBuilder<T>&& other);
|
||||
|
||||
template <typename Container>
|
||||
constexpr SimpleArray(Container& c) : SimpleArray(std::data(c), std::size(c))
|
||||
constexpr SimpleArray(Container& c) : SimpleArray(c.data(), c.size())
|
||||
{}
|
||||
constexpr SimpleArray(std::initializer_list<T> il) : SimpleArray(std::data(il), std::size(il))
|
||||
constexpr SimpleArray(const std::initializer_list<T>& il) : SimpleArray(il.begin(), il.size())
|
||||
{}
|
||||
~SimpleArray()
|
||||
{
|
||||
if constexpr (!std::is_pod<T>())
|
||||
{
|
||||
for (T *element = m_ptr, *end = m_ptr + m_size; element < end; element++)
|
||||
{
|
||||
element->~T();
|
||||
}
|
||||
}
|
||||
SimpleArrayHelper<T>::DestructArray(m_ptr, m_ptr + m_size);
|
||||
free(m_ptr);
|
||||
#ifdef TESTING
|
||||
SimpleArrayTesting::freeCount++;
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr T& operator[](size_t index) const
|
||||
{
|
||||
assert(index < m_size);
|
||||
return m_ptr[index];
|
||||
}
|
||||
T& operator[](size_t index) const { return m_ptr[index]; }
|
||||
|
||||
constexpr T* data() const { return m_ptr; }
|
||||
constexpr size_t size() const { return m_size; }
|
||||
@@ -203,25 +211,11 @@ private:
|
||||
#ifdef TESTING
|
||||
SimpleArrayTesting::reallocCount++;
|
||||
#endif
|
||||
if constexpr (!std::is_pod<T>())
|
||||
{
|
||||
// Call destructor for elements when sizing down.
|
||||
for (T *element = this->m_ptr + size, *end = this->m_ptr + this->m_size; element < end;
|
||||
element++)
|
||||
{
|
||||
element->~T();
|
||||
}
|
||||
}
|
||||
// Call destructor for elements when sizing down.
|
||||
SimpleArrayHelper<T>::DestructArray(this->m_ptr + size, this->m_ptr + this->m_size);
|
||||
this->m_ptr = static_cast<T*>(realloc(this->m_ptr, size * sizeof(T)));
|
||||
if constexpr (!std::is_pod<T>())
|
||||
{
|
||||
// Call constructor for elements when sizing up.
|
||||
for (T *element = this->m_ptr + this->m_size, *end = this->m_ptr + size; element < end;
|
||||
element++)
|
||||
{
|
||||
new (element) T();
|
||||
}
|
||||
}
|
||||
// Call constructor for elements when sizing up.
|
||||
SimpleArrayHelper<T>::DefaultConstructArray(this->m_ptr + this->m_size, this->m_ptr + size);
|
||||
this->m_size = size;
|
||||
}
|
||||
|
||||
@@ -229,7 +223,7 @@ private:
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr SimpleArray<T>::SimpleArray(SimpleArrayBuilder<T>&& other) : m_size(other.size())
|
||||
SimpleArray<T>::SimpleArray(SimpleArrayBuilder<T>&& other) : m_size(other.size())
|
||||
{
|
||||
// Bring the capacity down to the actual size (this should keep the same
|
||||
// ptr, but that's not guaranteed, so we copy the ptr after the realloc).
|
||||
|
||||
@@ -34,11 +34,9 @@ public:
|
||||
constexpr Span(const Span<U>& that) : Span(that.data(), that.size())
|
||||
{}
|
||||
constexpr Span(const Span&) = default;
|
||||
template <typename Container> constexpr Span(Container& c) : Span{std::data(c), std::size(c)} {}
|
||||
constexpr Span(std::initializer_list<T> il) : Span(std::data(il), std::size(il)) {}
|
||||
template <size_t N> constexpr Span(T (&a)[N]) : Span(a, N) {}
|
||||
template <typename Container> constexpr Span(Container& c) : Span(c.data(), c.size()) {}
|
||||
|
||||
constexpr T& operator[](size_t index) const
|
||||
T& operator[](size_t index) const
|
||||
{
|
||||
assert(index < m_Size);
|
||||
return m_Ptr[index];
|
||||
@@ -57,14 +55,9 @@ public:
|
||||
// returns byte-size of the entire span
|
||||
constexpr size_t size_bytes() const { return m_Size * sizeof(T); }
|
||||
|
||||
constexpr int count() const
|
||||
{
|
||||
const int n = static_cast<int>(m_Size);
|
||||
assert(n >= 0);
|
||||
return n;
|
||||
}
|
||||
constexpr size_t count() const { return m_Size; }
|
||||
|
||||
constexpr Span<T> subset(size_t offset, size_t size) const
|
||||
Span<T> subset(size_t offset, size_t size) const
|
||||
{
|
||||
assert(offset <= m_Size);
|
||||
assert(size <= m_Size - offset);
|
||||
@@ -82,6 +75,8 @@ public:
|
||||
typedef size_t size_type;
|
||||
};
|
||||
|
||||
template <typename T> Span<T> make_span(T* ptr, size_t size) { return Span<T>(ptr, size); }
|
||||
|
||||
} // namespace rive
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,5 +8,5 @@ using namespace rive;
|
||||
|
||||
std::unique_ptr<StateInstance> AnimationState::makeInstance(ArtboardInstance* instance) const
|
||||
{
|
||||
return std::make_unique<AnimationStateInstance>(this, instance);
|
||||
return rivestd::make_unique<AnimationStateInstance>(this, instance);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using namespace rive;
|
||||
|
||||
std::unique_ptr<StateInstance> BlendState1D::makeInstance(ArtboardInstance* instance) const
|
||||
{
|
||||
return std::make_unique<BlendState1DInstance>(this, instance);
|
||||
return rivestd::make_unique<BlendState1DInstance>(this, instance);
|
||||
}
|
||||
|
||||
StatusCode BlendState1D::import(ImportStack& importStack)
|
||||
|
||||
@@ -8,5 +8,5 @@ using namespace rive;
|
||||
|
||||
std::unique_ptr<StateInstance> BlendStateDirect::makeInstance(ArtboardInstance* instance) const
|
||||
{
|
||||
return std::make_unique<BlendStateDirectInstance>(this, instance);
|
||||
return rivestd::make_unique<BlendStateDirectInstance>(this, instance);
|
||||
}
|
||||
@@ -58,5 +58,5 @@ void LayerState::addTransition(StateTransition* transition) { m_Transitions.push
|
||||
|
||||
std::unique_ptr<StateInstance> LayerState::makeInstance(ArtboardInstance* instance) const
|
||||
{
|
||||
return std::make_unique<SystemStateInstance>(this, instance);
|
||||
return rivestd::make_unique<SystemStateInstance>(this, instance);
|
||||
}
|
||||
@@ -92,5 +92,5 @@ float LinearAnimation::globalToLocalSeconds(float seconds) const
|
||||
int direction = ((int)(seconds / (endSeconds() - startSeconds()))) % 2;
|
||||
return direction == 0 ? localTime + startSeconds() : endSeconds() - localTime;
|
||||
}
|
||||
RIVE_UNREACHABLE;
|
||||
RIVE_UNREACHABLE();
|
||||
}
|
||||
@@ -9,5 +9,5 @@ NestedLinearAnimation::~NestedLinearAnimation() {}
|
||||
void NestedLinearAnimation::initializeAnimation(ArtboardInstance* artboard)
|
||||
{
|
||||
m_AnimationInstance =
|
||||
std::make_unique<LinearAnimationInstance>(artboard->animation(animationId()), artboard);
|
||||
rivestd::make_unique<LinearAnimationInstance>(artboard->animation(animationId()), artboard);
|
||||
}
|
||||
@@ -434,7 +434,7 @@ StateMachineInstance::StateMachineInstance(const StateMachine* machine,
|
||||
auto shape = m_ArtboardInstance->resolve(id);
|
||||
if (shape != nullptr && shape->is<Shape>())
|
||||
{
|
||||
auto hs = std::make_unique<HitShape>(shape->as<Shape>());
|
||||
auto hs = rivestd::make_unique<HitShape>(shape->as<Shape>());
|
||||
hitShapeLookup[id] = hitShape = hs.get();
|
||||
m_HitShapes.push_back(std::move(hs));
|
||||
}
|
||||
|
||||
@@ -735,25 +735,25 @@ ArtboardInstance::~ArtboardInstance() { Counter::update(Counter::kArtboardInstan
|
||||
std::unique_ptr<LinearAnimationInstance> ArtboardInstance::animationAt(size_t index)
|
||||
{
|
||||
auto la = this->animation(index);
|
||||
return la ? std::make_unique<LinearAnimationInstance>(la, this) : nullptr;
|
||||
return la ? rivestd::make_unique<LinearAnimationInstance>(la, this) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<LinearAnimationInstance> ArtboardInstance::animationNamed(const std::string& name)
|
||||
{
|
||||
auto la = this->animation(name);
|
||||
return la ? std::make_unique<LinearAnimationInstance>(la, this) : nullptr;
|
||||
return la ? rivestd::make_unique<LinearAnimationInstance>(la, this) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<StateMachineInstance> ArtboardInstance::stateMachineAt(size_t index)
|
||||
{
|
||||
auto sm = this->stateMachine(index);
|
||||
return sm ? std::make_unique<StateMachineInstance>(sm, this) : nullptr;
|
||||
return sm ? rivestd::make_unique<StateMachineInstance>(sm, this) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<StateMachineInstance> ArtboardInstance::stateMachineNamed(const std::string& name)
|
||||
{
|
||||
auto sm = this->stateMachine(name);
|
||||
return sm ? std::make_unique<StateMachineInstance>(sm, this) : nullptr;
|
||||
return sm ? rivestd::make_unique<StateMachineInstance>(sm, this) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<StateMachineInstance> ArtboardInstance::defaultStateMachine()
|
||||
|
||||
@@ -385,7 +385,8 @@ rcp<ContourMeasure> ContourMeasureIter::tryNext()
|
||||
|
||||
for (; m_iter != m_end; ++m_iter)
|
||||
{
|
||||
auto [verb, iterPts] = *m_iter;
|
||||
PathVerb verb = std::get<0>(*m_iter);
|
||||
const Vec2D* iterPts = std::get<1>(*m_iter);
|
||||
if (verb == PathVerb::move)
|
||||
{
|
||||
if (!pts.empty())
|
||||
@@ -439,7 +440,7 @@ rcp<ContourMeasure> ContourMeasureIter::tryNext()
|
||||
}
|
||||
break;
|
||||
case PathVerb::move:
|
||||
RIVE_UNREACHABLE; // Handled above.
|
||||
RIVE_UNREACHABLE(); // Handled above.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -270,8 +270,10 @@ void RawPath::rewind()
|
||||
|
||||
void RawPath::addTo(CommandPath* result) const
|
||||
{
|
||||
for (auto [verb, pts] : *this)
|
||||
for (auto iter : *this)
|
||||
{
|
||||
PathVerb verb = std::get<0>(iter);
|
||||
const Vec2D* pts = std::get<1>(iter);
|
||||
switch (verb)
|
||||
{
|
||||
case PathVerb::move:
|
||||
@@ -287,7 +289,7 @@ void RawPath::addTo(CommandPath* result) const
|
||||
result->close();
|
||||
break;
|
||||
case PathVerb::quad:
|
||||
RIVE_UNREACHABLE;
|
||||
RIVE_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ FlattenedPath* Path::makeFlat(bool transformToParent)
|
||||
deletePrevious = true;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
RIVE_FALLTHROUGH;
|
||||
}
|
||||
default:
|
||||
if (deletePrevious)
|
||||
|
||||
@@ -141,12 +141,12 @@ public:
|
||||
// Returns a full-formed RenderPath -- can be treated as immutable
|
||||
std::unique_ptr<RenderPath> SokolFactory::makeRenderPath(RawPath& rawPath, FillRule rule)
|
||||
{
|
||||
return std::make_unique<SokolRenderPath>(rawPath, rule);
|
||||
return rivestd::make_unique<SokolRenderPath>(rawPath, rule);
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderPath> SokolFactory::makeEmptyRenderPath()
|
||||
{
|
||||
return std::make_unique<SokolRenderPath>();
|
||||
return rivestd::make_unique<SokolRenderPath>();
|
||||
}
|
||||
|
||||
class SokolBuffer : public RenderBuffer
|
||||
@@ -740,7 +740,7 @@ public:
|
||||
m_strokeDirty = false;
|
||||
break;
|
||||
case RenderPaintStyle::stroke:
|
||||
m_stroke = std::make_unique<ContourStroke>();
|
||||
m_stroke = rivestd::make_unique<ContourStroke>();
|
||||
m_strokeDirty = true;
|
||||
break;
|
||||
}
|
||||
@@ -897,7 +897,7 @@ public:
|
||||
|
||||
std::unique_ptr<RenderPaint> SokolFactory::makeRenderPaint()
|
||||
{
|
||||
return std::make_unique<SokolRenderPaint>();
|
||||
return rivestd::make_unique<SokolRenderPaint>();
|
||||
}
|
||||
|
||||
void SokolTessRenderer::restore()
|
||||
|
||||
@@ -40,7 +40,7 @@ template <typename T> bool checkAs(uint64_t value)
|
||||
uint8_t* p = storage;
|
||||
|
||||
p = packvarint(storage, value);
|
||||
rive::BinaryReader reader(rive::Span(storage, p - storage));
|
||||
rive::BinaryReader reader(rive::make_span(storage, p - storage));
|
||||
|
||||
auto newValue = reader.readVarUintAs<T>();
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class ClippingFactory : public rive::NoOpFactory
|
||||
std::unique_ptr<rive::RenderPath> makeRenderPath(rive::RawPath& rawPath,
|
||||
rive::FillRule) override
|
||||
{
|
||||
return std::make_unique<ClipTestRenderPath>(rawPath);
|
||||
return rivestd::make_unique<ClipTestRenderPath>(rawPath);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ TEST_CASE("multi-contours", "[contourmeasure]")
|
||||
{3, 0},
|
||||
{3, 4},
|
||||
};
|
||||
auto span = Span(pts, sizeof(pts) / sizeof(pts[0]));
|
||||
auto span = make_span(pts, sizeof(pts) / sizeof(pts[0]));
|
||||
|
||||
// We expect 3 measurable contours out of this: 7, 16, 7
|
||||
// the others should be skipped since they are empty (len == 0)
|
||||
|
||||
@@ -55,5 +55,5 @@ TEST_CASE("hittest-mesh", "[hittest]")
|
||||
1,
|
||||
2,
|
||||
};
|
||||
REQUIRE(HitTester::testMesh(area, Span(verts, 3), Span(indices, 3)));
|
||||
REQUIRE(HitTester::testMesh(area, make_span(verts, 3), make_span(indices, 3)));
|
||||
}
|
||||
|
||||
@@ -107,12 +107,14 @@ TEST_CASE("findMaxScale", "[Mat2D]")
|
||||
// success = givingNegativeNearlyZeros.getMinMaxScales(scales);
|
||||
// CHECK(success && 0 == scales[0]);
|
||||
|
||||
Mat2D baseMats[] = {scale, rot90Scale, rotate, translate};
|
||||
Mat2D mats[2 * std::size(baseMats)];
|
||||
for (size_t i = 0; i < std::size(baseMats); ++i)
|
||||
constexpr int kNumBaseMats = 4;
|
||||
Mat2D baseMats[kNumBaseMats] = {scale, rot90Scale, rotate, translate};
|
||||
constexpr int kNumMats = 2 * kNumBaseMats;
|
||||
Mat2D mats[kNumMats];
|
||||
for (size_t i = 0; i < kNumBaseMats; ++i)
|
||||
{
|
||||
mats[i] = baseMats[i];
|
||||
bool invertible = mats[i].invert(&mats[i + std::size(baseMats)]);
|
||||
bool invertible = mats[i].invert(&mats[i + kNumBaseMats]);
|
||||
REQUIRE(invertible);
|
||||
}
|
||||
srand(0);
|
||||
@@ -121,7 +123,7 @@ TEST_CASE("findMaxScale", "[Mat2D]")
|
||||
Mat2D mat;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
int x = rand() % std::size(mats);
|
||||
int x = rand() % kNumMats;
|
||||
mat = mats[x] * mat;
|
||||
}
|
||||
|
||||
@@ -135,8 +137,9 @@ TEST_CASE("findMaxScale", "[Mat2D]")
|
||||
static const float gVectorScaleTol = (105 * 1.f) / 100;
|
||||
static const float gCloseScaleTol = (97 * 1.f) / 100;
|
||||
float max = 0, min = std::numeric_limits<float>::max();
|
||||
Vec2D vectors[1000];
|
||||
for (size_t i = 0; i < std::size(vectors); ++i)
|
||||
constexpr int kNumVectors = 1000;
|
||||
Vec2D vectors[kNumVectors];
|
||||
for (size_t i = 0; i < kNumVectors; ++i)
|
||||
{
|
||||
vectors[i].x = rand() * 2.f / static_cast<float>(RAND_MAX) - 1;
|
||||
vectors[i].y = rand() * 2.f / static_cast<float>(RAND_MAX) - 1;
|
||||
@@ -144,7 +147,7 @@ TEST_CASE("findMaxScale", "[Mat2D]")
|
||||
vectors[i] = {mat[0] * vectors[i].x + mat[2] * vectors[i].y,
|
||||
mat[1] * vectors[i].x + mat[3] * vectors[i].y};
|
||||
}
|
||||
for (size_t i = 0; i < std::size(vectors); ++i)
|
||||
for (size_t i = 0; i < kNumVectors; ++i)
|
||||
{
|
||||
float d = vectors[i].length();
|
||||
REQUIRE(d / maxScale < gVectorScaleTol);
|
||||
|
||||
@@ -75,7 +75,7 @@ class TestNoOpFactory : public rive::NoOpFactory
|
||||
public:
|
||||
std::unique_ptr<rive::RenderPath> makeEmptyRenderPath() override
|
||||
{
|
||||
return std::make_unique<TestRenderPath>();
|
||||
return rivestd::make_unique<TestRenderPath>();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -91,7 +91,8 @@ static void check_iter(RawPath::Iter& iter,
|
||||
std::vector<Vec2D> expectedPts)
|
||||
{
|
||||
REQUIRE(iter != end);
|
||||
auto [verb, pts] = *iter;
|
||||
PathVerb verb = std::get<0>(*iter);
|
||||
const Vec2D* pts = std::get<1>(*iter);
|
||||
REQUIRE(verb == expectedVerb);
|
||||
for (size_t i = 0; i < expectedPts.size(); ++i)
|
||||
{
|
||||
@@ -113,7 +114,8 @@ TEST_CASE("rawpath-iter", "[rawpath]")
|
||||
rp.quadTo(5, 6, 7, 8);
|
||||
rp.cubicTo(9, 10, 11, 12, 13, 14);
|
||||
rp.close();
|
||||
auto [iter, end] = std::make_tuple(rp.begin(), rp.end());
|
||||
auto iter = rp.begin();
|
||||
auto end = rp.end();
|
||||
check_iter(iter, end, PathVerb::move, {{1, 2}});
|
||||
check_iter(iter, end, PathVerb::line, {{1, 2}, {3, 4}});
|
||||
check_iter(iter, end, PathVerb::quad, {{3, 4}, {5, 6}, {7, 8}});
|
||||
|
||||
@@ -289,8 +289,6 @@ TEST_CASE("clamp", "[simd]")
|
||||
|
||||
// Returns lo if x == NaN, but std::clamp() returns NaN.
|
||||
CHECK(simd::clamp<float, 1>(kNaN, 1, 2).x == 1);
|
||||
CHECK(std::clamp<float>(kNaN, 1, 2) != 1);
|
||||
CHECK(std::isnan(std::clamp<float>(kNaN, 1, 2)));
|
||||
|
||||
// Returns hi if hi <= lo.
|
||||
CHECK(simd::clamp<float, 1>(3, 2, 1).x == 1);
|
||||
|
||||
@@ -19,7 +19,8 @@ TEST_CASE("array initializes as expected", "[simple array]")
|
||||
|
||||
TEST_CASE("simple array can be created", "[simple array]")
|
||||
{
|
||||
SimpleArray<int> array({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
SimpleArray<int> array(v);
|
||||
|
||||
REQUIRE(!array.empty());
|
||||
REQUIRE(array.size() == 10);
|
||||
@@ -40,7 +41,7 @@ TEST_CASE("simple array can be created", "[simple array]")
|
||||
TEST_CASE("can iterate simple array", "[simple array]")
|
||||
{
|
||||
const int carray[] = {2, 4, 8, 16};
|
||||
SimpleArray<int> array(carray);
|
||||
SimpleArray<int> array(carray, 4);
|
||||
int expect = 2;
|
||||
for (auto value : array)
|
||||
{
|
||||
@@ -89,7 +90,8 @@ static SimpleArray<StructA> buildStructs()
|
||||
{
|
||||
SimpleArrayTesting::resetCounters();
|
||||
|
||||
SimpleArray<uint32_t> numbersA({33, 22, 44, 66});
|
||||
std::vector<uint32_t> vA{33, 22, 44, 66};
|
||||
SimpleArray<uint32_t> numbersA(vA);
|
||||
|
||||
StructA dataA = {std::move(numbersA)};
|
||||
// We moved the data so expect only one alloc and 0 reallocs.
|
||||
@@ -98,7 +100,8 @@ static SimpleArray<StructA> buildStructs()
|
||||
REQUIRE(dataA.numbers.size() == 4);
|
||||
REQUIRE(numbersA.size() == 0);
|
||||
|
||||
SimpleArray<uint32_t> numbersB({1, 2, 3});
|
||||
std::vector<uint32_t> vB{1, 2, 3};
|
||||
SimpleArray<uint32_t> numbersB(vB);
|
||||
|
||||
StructA dataB = {std::move(numbersB)};
|
||||
REQUIRE(SimpleArrayTesting::mallocCount == 2);
|
||||
|
||||
@@ -55,9 +55,7 @@ TEST_CASE("const-and-containers", "[span]")
|
||||
funcb({carray, 4});
|
||||
|
||||
int array[] = {1, 2, 3, 4};
|
||||
funca(array);
|
||||
funca({array, 4});
|
||||
funcb(array);
|
||||
funcb({array, 4});
|
||||
|
||||
std::vector<int> v;
|
||||
@@ -69,7 +67,7 @@ TEST_CASE("can iterate span", "[span]")
|
||||
{
|
||||
const int carray[] = {2, 4, 8, 16};
|
||||
|
||||
auto span = Span(carray);
|
||||
auto span = make_span(carray, 4);
|
||||
int expect = 2;
|
||||
for (auto value : span)
|
||||
{
|
||||
|
||||
@@ -66,17 +66,17 @@ rcp<RenderShader> NoOpFactory::makeRadialGradient(float cx,
|
||||
|
||||
std::unique_ptr<RenderPath> NoOpFactory::makeRenderPath(RawPath&, FillRule)
|
||||
{
|
||||
return std::make_unique<NoOpRenderPath>();
|
||||
return rivestd::make_unique<NoOpRenderPath>();
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderPath> NoOpFactory::makeEmptyRenderPath()
|
||||
{
|
||||
return std::make_unique<NoOpRenderPath>();
|
||||
return rivestd::make_unique<NoOpRenderPath>();
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderPaint> NoOpFactory::makeRenderPaint()
|
||||
{
|
||||
return std::make_unique<NoOpRenderPaint>();
|
||||
return rivestd::make_unique<NoOpRenderPaint>();
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderImage> NoOpFactory::decodeImage(Span<const uint8_t>)
|
||||
|
||||
@@ -40,9 +40,9 @@ class AtlasPackerFactory : public NoOpFactory
|
||||
bitmap->pixelFormat(Bitmap::PixelFormat::RGBA);
|
||||
}
|
||||
|
||||
return std::make_unique<AtlasRenderImage>(bitmap->bytes(),
|
||||
bitmap->width(),
|
||||
bitmap->height());
|
||||
return rivestd::make_unique<AtlasRenderImage>(bitmap->bytes(),
|
||||
bitmap->width(),
|
||||
bitmap->height());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -236,10 +236,10 @@ void SampleAtlasResolver::loadContents(FileAsset& asset)
|
||||
// renderer (and hence will know which RenderImage they need to
|
||||
// make).
|
||||
|
||||
imageAsset->renderImage(std::make_unique<SokolRenderImage>(imageResource,
|
||||
location.width,
|
||||
location.height,
|
||||
location.transform));
|
||||
imageAsset->renderImage(rivestd::make_unique<SokolRenderImage>(imageResource,
|
||||
location.width,
|
||||
location.height,
|
||||
location.transform));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<ViewerHost> ViewerHost::Make() { return std::make_unique<SkiaViewerHost>(); }
|
||||
std::unique_ptr<ViewerHost> ViewerHost::Make() { return rivestd::make_unique<SkiaViewerHost>(); }
|
||||
|
||||
rive::Factory* ViewerHost::Factory()
|
||||
{
|
||||
|
||||
@@ -100,7 +100,7 @@ void Bitmap::pixelFormat(PixelFormat format)
|
||||
return;
|
||||
}
|
||||
auto nextByteSize = byteSize(format);
|
||||
auto nextBytes = std::make_unique<uint8_t[]>(nextByteSize);
|
||||
auto nextBytes = rivestd::make_unique<uint8_t[]>(nextByteSize);
|
||||
|
||||
auto fromBytesPerPixel = bytesPerPixel(m_PixelFormat);
|
||||
auto toBytesPerPixel = bytesPerPixel(format);
|
||||
|
||||
@@ -135,6 +135,6 @@ std::unique_ptr<Bitmap> DecodePng(rive::Span<const uint8_t> bytes)
|
||||
pixelFormat = Bitmap::PixelFormat::R;
|
||||
break;
|
||||
}
|
||||
return std::make_unique<Bitmap>(width, height, pixelFormat, pixelBuffer);
|
||||
return rivestd::make_unique<Bitmap>(width, height, pixelFormat, pixelBuffer);
|
||||
}
|
||||
#endif
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
|
||||
bool init(sg_pass_action*, int width, int height) override
|
||||
{
|
||||
m_renderer = std::make_unique<rive::SokolTessRenderer>();
|
||||
m_renderer = rivestd::make_unique<rive::SokolTessRenderer>();
|
||||
m_renderer->orthographicProjection(0.0f, width, height, 0.0f, 0.0f, 1.0f);
|
||||
return true;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<ViewerHost> ViewerHost::Make() { return std::make_unique<TessViewerHost>(); }
|
||||
std::unique_ptr<ViewerHost> ViewerHost::Make() { return rivestd::make_unique<TessViewerHost>(); }
|
||||
|
||||
rive::Factory* ViewerHost::Factory()
|
||||
{
|
||||
|
||||
@@ -26,10 +26,10 @@ std::unique_ptr<rive::RenderImage> ViewerSokolFactory::decodeImage(rive::Span<co
|
||||
new rive::SokolRenderImageResource(bitmap->bytes(), bitmap->width(), bitmap->height()));
|
||||
|
||||
static rive::Mat2D identity;
|
||||
return std::make_unique<rive::SokolRenderImage>(imageGpuResource,
|
||||
bitmap->width(),
|
||||
bitmap->height(),
|
||||
identity);
|
||||
return rivestd::make_unique<rive::SokolRenderImage>(imageGpuResource,
|
||||
bitmap->width(),
|
||||
bitmap->height(),
|
||||
identity);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ std::unique_ptr<ViewerContent> ViewerContent::Image(const char filename[])
|
||||
auto image = RiveFactory()->decodeImage(bytes);
|
||||
if (image)
|
||||
{
|
||||
return std::make_unique<ImageContent>(std::move(image));
|
||||
return rivestd::make_unique<ImageContent>(std::move(image));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ std::unique_ptr<ViewerContent> ViewerContent::Scene(const char filename[])
|
||||
auto bytes = LoadFile(filename);
|
||||
if (auto file = rive::File::import(bytes, RiveFactory()))
|
||||
{
|
||||
return std::make_unique<SceneContent>(filename, std::move(file));
|
||||
return rivestd::make_unique<SceneContent>(filename, std::move(file));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -392,7 +392,7 @@ std::unique_ptr<ViewerContent> ViewerContent::Text(const char filename[])
|
||||
{
|
||||
if (ends_width(filename, ".svg"))
|
||||
{
|
||||
return std::make_unique<TextContent>();
|
||||
return rivestd::make_unique<TextContent>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ public:
|
||||
|
||||
std::unique_ptr<ViewerContent> ViewerContent::TextPath(const char filename[])
|
||||
{
|
||||
return std::make_unique<TextPathContent>();
|
||||
return rivestd::make_unique<TextPathContent>();
|
||||
}
|
||||
#else
|
||||
std::unique_ptr<ViewerContent> ViewerContent::TextPath(const char filename[]) { return nullptr; }
|
||||
|
||||
@@ -170,5 +170,5 @@ public:
|
||||
|
||||
std::unique_ptr<ViewerContent> ViewerContent::TrimPath(const char[])
|
||||
{
|
||||
return std::make_unique<TrimPathContent>();
|
||||
return rivestd::make_unique<TrimPathContent>();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user