Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,466 @@
/*
* Copyright (c) 2016, Blender Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <COPYRIGHT HOLDER> 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.
*/
/** \file curve_fit_corners_detect.c
* \ingroup curve_fit
*/
#include <math.h>
#include <float.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "../curve_fit_nd.h"
typedef unsigned int uint;
#include "curve_fit_inline.h"
#ifdef _MSC_VER
# define alloca(size) _alloca(size)
#endif
#if !defined(_MSC_VER)
# define USE_VLA
#endif
#ifdef USE_VLA
# ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wvla"
# endif
#else
# ifdef __GNUC__
# pragma GCC diagnostic error "-Wvla"
# endif
#endif
/* -------------------------------------------------------------------- */
/** \name Simple Vector Math Lib
* \{ */
static double cos_vnvnvn(
const double v0[], const double v1[], const double v2[],
const uint dims)
{
#ifdef USE_VLA
double dvec0[dims];
double dvec1[dims];
#else
double *dvec0 = alloca(sizeof(double) * dims);
double *dvec1 = alloca(sizeof(double) * dims);
#endif
normalize_vn_vnvn(dvec0, v0, v1, dims);
normalize_vn_vnvn(dvec1, v1, v2, dims);
double d = dot_vnvn(dvec0, dvec1, dims);
/* Sanity check. */
d = max(-1.0, min(1.0, d));
return d;
}
static double angle_vnvnvn(
const double v0[], const double v1[], const double v2[],
const uint dims)
{
return acos(cos_vnvnvn(v0, v1, v2, dims));
}
static bool isect_line_sphere_vn(
const double l1[],
const double l2[],
const double sp[],
const double r,
uint dims,
double r_p1[]
#if 0 /* UNUSED */
double r_p2[]
#endif
)
{
#ifdef USE_VLA
double ldir[dims];
double tvec[dims];
#else
double *ldir = alloca(sizeof(double) * dims);
double *tvec = alloca(sizeof(double) * dims);
#endif
sub_vn_vnvn(ldir, l2, l1, dims);
sub_vn_vnvn(tvec, l1, sp, dims);
const double a = len_squared_vn(ldir, dims);
const double b = 2.0 * dot_vnvn(ldir, tvec, dims);
const double c = len_squared_vn(sp, dims) + len_squared_vn(l1, dims) - (2.0 * dot_vnvn(sp, l1, dims)) - sq(r);
const double i = b * b - 4.0 * a * c;
if ((i < 0.0) || (a == 0.0)) {
return false;
}
else if (i == 0.0) {
/* One intersection. */
const double mu = -b / (2.0 * a);
mul_vnvn_fl(r_p1, ldir, mu, dims);
iadd_vnvn(r_p1, l1, dims);
return true;
}
else if (i > 0.0) {
/* Avoid calculating twice. */
const double i_sqrt = sqrt(i);
double mu;
/* Note: when l1 is inside the sphere and l2 is outside,
* the first intersection point will always be between the pair. */
/* First intersection. */
mu = (-b + i_sqrt) / (2.0 * a);
mul_vnvn_fl(r_p1, ldir, mu, dims);
iadd_vnvn(r_p1, l1, dims);
#if 0
/* Second intersection. */
mu = (-b - i_sqrt) / (2.0 * a);
mul_vnvn_fl(r_p2, ldir, mu, dims);
iadd_vnvn(r_p2, l1, dims);
#endif
return true;
}
else {
return false;
}
}
/** \} */
/* -------------------------------------------------------------------- */
static bool point_corner_measure(
const double *points,
const uint points_len,
const uint i,
const uint i_prev_init,
const uint i_next_init,
const double radius,
const uint samples_max,
const uint dims,
double r_p_prev[], uint *r_i_prev_next,
double r_p_next[], uint *r_i_next_prev)
{
const double *p = &points[i * dims];
const double radius_sq = sq(radius);
uint sample;
uint i_prev = i_prev_init;
uint i_prev_next = i_prev + 1;
sample = 0;
while (true) {
if ((i_prev == -1) || (sample++ > samples_max)) {
return false;
}
else if (len_squared_vnvn(p, &points[i_prev * dims], dims) < radius_sq) {
i_prev -= 1;
}
else {
break;
}
}
uint i_next = i_next_init;
uint i_next_prev = i_next - 1;
sample = 0;
while (true) {
if ((i_next == points_len) || (sample++ > samples_max)) {
return false;
}
else if (len_squared_vnvn(p, &points[i_next * dims], dims) < radius_sq) {
i_next += 1;
}
else {
break;
}
}
/* Find points on the sphere. */
if (!isect_line_sphere_vn(
&points[i_prev * dims], &points[i_prev_next * dims], p, radius, dims,
r_p_prev))
{
return false;
}
if (!isect_line_sphere_vn(
&points[i_next * dims], &points[i_next_prev * dims], p, radius, dims,
r_p_next))
{
return false;
}
*r_i_prev_next = i_prev_next;
*r_i_next_prev = i_next_prev;
return true;
}
static double point_corner_angle(
const double *points,
const uint points_len,
const uint i,
const double radius_mid,
const double radius_max,
const double angle_threshold,
const double angle_threshold_cos,
/* Prevent locking up when for example `radius_min` is very large
* (possibly larger than the curve).
* In this case we would end up checking every point from every other point,
* never reaching one that was outside the `radius_min`. */
const uint samples_max,
const uint dims)
{
assert(angle_threshold_cos == cos(angle_threshold));
if (i == 0 || i == points_len - 1) {
return 0.0;
}
const double *p = &points[i * dims];
/* Initial test. */
if (cos_vnvnvn(&points[(i - 1) * dims], p, &points[(i + 1) * dims], dims) > angle_threshold_cos) {
return 0.0;
}
#ifdef USE_VLA
double p_mid_prev[dims];
double p_mid_next[dims];
#else
double *p_mid_prev = alloca(sizeof(double) * dims);
double *p_mid_next = alloca(sizeof(double) * dims);
#endif
uint i_mid_prev_next, i_mid_next_prev;
if (point_corner_measure(
points, points_len,
i, i - 1, i + 1,
radius_mid,
samples_max,
dims,
p_mid_prev, &i_mid_prev_next,
p_mid_next, &i_mid_next_prev))
{
const double angle_mid_cos = cos_vnvnvn(p_mid_prev, p, p_mid_next, dims);
/* Compare as cos and flip direction. */
/* if (angle_mid > angle_threshold) { */
if (angle_mid_cos < angle_threshold_cos) {
#ifdef USE_VLA
double p_max_prev[dims];
double p_max_next[dims];
#else
double *p_max_prev = alloca(sizeof(double) * dims);
double *p_max_next = alloca(sizeof(double) * dims);
#endif
uint i_max_prev_next, i_max_next_prev;
if (point_corner_measure(
points, points_len,
i, i - 1, i + 1,
radius_max,
samples_max,
dims,
p_max_prev, &i_max_prev_next,
p_max_next, &i_max_next_prev))
{
const double angle_mid = acos(angle_mid_cos);
const double angle_max = angle_vnvnvn(p_max_prev, p, p_max_next, dims) / 2.0;
const double angle_diff = angle_mid - angle_max;
if (angle_diff > angle_threshold) {
return angle_diff;
}
}
}
}
return 0.0;
}
int curve_fit_corners_detect_db(
const double *points,
const uint points_len,
const uint dims,
const double radius_min, /* ignore values below this */
const double radius_max, /* ignore values above this */
const uint samples_max,
const double angle_threshold,
uint **r_corners,
uint *r_corners_len)
{
const double angle_threshold_cos = cos(angle_threshold);
uint corners_len = 0;
/* Use the difference in angle between the mid-max radii
* to detect the difference between a corner and a sharp turn. */
const double radius_mid = (radius_min + radius_max) / 2.0;
/* We could ignore first/last, but simple to keep aligned with the point array. */
double *points_angle = malloc(sizeof(double) * points_len);
points_angle[0] = 0.0;
*r_corners = NULL;
*r_corners_len = 0;
for (uint i = 0; i < points_len; i++) {
points_angle[i] = point_corner_angle(
points, points_len, i,
radius_mid, radius_max,
angle_threshold, angle_threshold_cos,
samples_max,
dims);
if (points_angle[i] != 0.0) {
corners_len++;
}
}
if (corners_len == 0) {
free(points_angle);
return 0;
}
/* Clean angle limits!
*
* How this works:
* - Find contiguous 'corners' (where the distance is less or equal to the error threshold).
* - Keep track of the corner with the highest angle
* - Clear every other angle (so they're ignored when setting corners). */
{
const double radius_min_sq = sq(radius_min);
uint i_span_start = 0;
while (i_span_start < points_len) {
uint i_span_end = i_span_start;
if (points_angle[i_span_start] != 0.0) {
uint i_next = i_span_start + 1;
uint i_best = i_span_start;
while (i_next < points_len) {
if ((points_angle[i_next] == 0.0) ||
(len_squared_vnvn(
&points[(i_next - 1) * dims],
&points[i_next * dims], dims) > radius_min_sq))
{
break;
}
else {
if (points_angle[i_best] < points_angle[i_next]) {
i_best = i_next;
}
i_span_end = i_next;
i_next += 1;
}
}
if (i_span_start != i_span_end) {
uint i = i_span_start;
while (i <= i_span_end) {
if (i != i_best) {
/* We could use some other error code. */
assert(points_angle[i] != 0.0);
points_angle[i] = 0.0;
corners_len--;
}
i += 1;
}
}
}
i_span_start = i_span_end + 1;
}
}
/* End angle limit cleaning! */
corners_len += 2; /* first and last */
uint *corners = malloc(sizeof(uint) * corners_len);
uint i_corner = 0;
corners[i_corner++] = 0;
for (uint i = 0; i < points_len; i++) {
if (points_angle[i] != 0.0) {
corners[i_corner++] = i;
}
}
corners[i_corner++] = points_len - 1;
assert(i_corner == corners_len);
free(points_angle);
*r_corners = corners;
*r_corners_len = corners_len;
return 0;
}
int curve_fit_corners_detect_fl(
const float *points,
const uint points_len,
const uint dims,
const float radius_min, /* ignore values below this */
const float radius_max, /* ignore values above this */
const uint samples_max,
const float angle_threshold,
uint **r_corners,
uint *r_corners_len)
{
const uint points_flat_len = points_len * dims;
double *points_db = malloc(sizeof(double) * points_flat_len);
for (uint i = 0; i < points_flat_len; i++) {
points_db[i] = (double)points[i];
}
int result = curve_fit_corners_detect_db(
points_db, points_len,
dims,
radius_min, radius_max,
samples_max,
angle_threshold,
r_corners, r_corners_len);
free(points_db);
return result;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,316 @@
/*
* Copyright (c) 2016, Blender Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <COPYRIGHT HOLDER> 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.
*/
/** \file curve_fit_inline.h
* \ingroup curve_fit
*/
/* -------------------------------------------------------------------- */
/** \name Simple Vector Math Lib
* \{ */
#ifdef _MSC_VER
# define MINLINE static __forceinline
#else
# define MINLINE static inline
#endif
MINLINE double sq(const double d)
{
return d * d;
}
#ifndef _MSC_VER
MINLINE double min(const double a, const double b)
{
return b < a ? b : a;
}
MINLINE double max(const double a, const double b)
{
return a < b ? b : a;
}
#endif
MINLINE void zero_vn(
double v0[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v0[j] = 0.0;
}
}
MINLINE void flip_vn_vnvn(
double v_out[], const double v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] = v0[j] + (v0[j] - v1[j]);
}
}
MINLINE void copy_vnvn(
double v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v0[j] = v1[j];
}
}
MINLINE void copy_vnfl_vndb(
float v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v0[j] = (float)v1[j];
}
}
MINLINE void copy_vndb_vnfl(
double v0[], const float v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v0[j] = (double)v1[j];
}
}
MINLINE double dot_vnvn(
const double v0[], const double v1[], const uint dims)
{
double d = 0.0;
for (uint j = 0; j < dims; j++) {
d += v0[j] * v1[j];
}
return d;
}
MINLINE void add_vn_vnvn(
double v_out[], const double v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] = v0[j] + v1[j];
}
}
MINLINE void sub_vn_vnvn(
double v_out[], const double v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] = v0[j] - v1[j];
}
}
MINLINE void iadd_vnvn(
double v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v0[j] += v1[j];
}
}
MINLINE void isub_vnvn(
double v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
v0[j] -= v1[j];
}
}
MINLINE void madd_vn_vnvn_fl(
double v_out[],
const double v0[], const double v1[],
const double f, const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] = v0[j] + v1[j] * f;
}
}
MINLINE void msub_vn_vnvn_fl(
double v_out[],
const double v0[], const double v1[],
const double f, const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] = v0[j] - v1[j] * f;
}
}
MINLINE void miadd_vn_vn_fl(
double v_out[], const double v0[], double f, const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] += v0[j] * f;
}
}
#if 0
MINLINE void misub_vn_vn_fl(
double v_out[], const double v0[], double f, const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] -= v0[j] * f;
}
}
#endif
MINLINE void mul_vnvn_fl(
double v_out[],
const double v0[], const double f, const uint dims)
{
for (uint j = 0; j < dims; j++) {
v_out[j] = v0[j] * f;
}
}
MINLINE void imul_vn_fl(double v0[], const double f, const uint dims)
{
for (uint j = 0; j < dims; j++) {
v0[j] *= f;
}
}
MINLINE double len_squared_vnvn(
const double v0[], const double v1[], const uint dims)
{
double d = 0.0;
for (uint j = 0; j < dims; j++) {
d += sq(v0[j] - v1[j]);
}
return d;
}
MINLINE double len_squared_vn(
const double v0[], const uint dims)
{
double d = 0.0;
for (uint j = 0; j < dims; j++) {
d += sq(v0[j]);
}
return d;
}
MINLINE double len_vnvn(
const double v0[], const double v1[], const uint dims)
{
return sqrt(len_squared_vnvn(v0, v1, dims));
}
MINLINE double len_vn(
const double v0[], const uint dims)
{
return sqrt(len_squared_vn(v0, dims));
}
/* Special case: save us negating a copy, then getting the length. */
MINLINE double len_squared_negated_vnvn(
const double v0[], const double v1[], const uint dims)
{
double d = 0.0;
for (uint j = 0; j < dims; j++) {
d += sq(v0[j] + v1[j]);
}
return d;
}
MINLINE double len_negated_vnvn(
const double v0[], const double v1[], const uint dims)
{
return sqrt(len_squared_negated_vnvn(v0, v1, dims));
}
MINLINE double normalize_vn(
double v0[], const uint dims)
{
double d = len_squared_vn(v0, dims);
if (d != 0.0 && ((d = sqrt(d)) != 0.0)) {
imul_vn_fl(v0, 1.0 / d, dims);
}
return d;
}
/* `v_out = (v0 - v1).normalized()`. */
MINLINE double normalize_vn_vnvn(
double v_out[],
const double v0[], const double v1[], const uint dims)
{
double d = 0.0;
for (uint j = 0; j < dims; j++) {
double a = v0[j] - v1[j];
d += sq(a);
v_out[j] = a;
}
if (d != 0.0 && ((d = sqrt(d)) != 0.0)) {
imul_vn_fl(v_out, 1.0 / d, dims);
}
return d;
}
MINLINE bool is_almost_zero_ex(double val, double eps)
{
return (-eps < val) && (val < eps);
}
MINLINE bool is_almost_zero(double val)
{
return is_almost_zero_ex(val, 1e-8);
}
MINLINE bool equals_vnvn(
const double v0[], const double v1[], const uint dims)
{
for (uint j = 0; j < dims; j++) {
if (v0[j] != v1[j]) {
return false;
}
}
return true;
}
MINLINE void project_vn_vnvn(
double v_out[], const double p[], const double v_proj[], const uint dims)
{
const double mul = dot_vnvn(p, v_proj, dims) / dot_vnvn(v_proj, v_proj, dims);
mul_vnvn_fl(v_out, v_proj, mul, dims);
}
MINLINE void project_vn_vnvn_normalized(
double v_out[], const double p[], const double v_proj[], const uint dims)
{
const double mul = dot_vnvn(p, v_proj, dims);
mul_vnvn_fl(v_out, v_proj, mul, dims);
}
MINLINE void project_plane_vn_vnvn_normalized(
double v_out[], const double v[], const double v_plane[], const uint dims)
{
assert(v != v_out);
project_vn_vnvn_normalized(v_out, v, v_plane, dims);
sub_vn_vnvn(v_out, v, v_out, dims);
}
/** \} */

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2016, Campbell Barton.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <COPYRIGHT HOLDER> 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 __CURVE_FIT_INTERN_H__
#define __CURVE_FIT_INTERN_H__
#ifndef __CURVE_FIT_UINT_DEFINED__
#define __CURVE_FIT_UINT_DEFINED__
typedef unsigned int uint;
#endif
/**
* Internal header for shared declarations between curve_fit_cubic.c
* and curve_fit_cubic_refit.c.
*/
/* Split point calculation functions (implemented in curve_fit_cubic.c) */
#define SPLIT_POINT_INVALID ((uint)-1)
uint split_point_find_sign_change(
const double *points,
const uint points_len,
const uint index_l, const uint index_r,
const uint dims);
uint split_point_find_max_distance(
const double *points,
const uint points_len,
const uint index_l, const uint index_r,
const uint dims);
uint split_point_find_max_on_axis(
const double *points,
const uint points_len,
const uint index_l, const uint index_r,
const double *axis,
const uint dims);
uint split_point_find_inflection(
const double *points,
const uint points_len,
const uint index_l, const uint index_r,
const uint dims);
#endif /* __CURVE_FIT_INTERN_H__ */

View File

@@ -0,0 +1,221 @@
/*
* Copyright (c) 2016, Blender Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <COPYRIGHT HOLDER> 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.
*/
/**
* \file generic_alloc_impl.h
* \ingroup curve_fit
*
* Simple Memory Chunking Allocator
* ================================
*
* Defines need to be set:
* - #TPOOL_IMPL_PREFIX: Prefix to use for the API.
* - #TPOOL_ALLOC_TYPE: Struct type this pool handles.
* - #TPOOL_STRUCT: Name for pool struct name.
* - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
*
* \note #TPOOL_ALLOC_TYPE must be at least `sizeof(void *)`.
*
* Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
*
* - *_pool_create()
* - *_pool_destroy()
* - *_pool_clear()
*
* - *_pool_elem_alloc()
* - *_pool_elem_calloc()
* - *_pool_elem_free()
*/
/* Check we're not building directly. */
#if !defined(TPOOL_IMPL_PREFIX) || \
!defined(TPOOL_ALLOC_TYPE) || \
!defined(TPOOL_STRUCT)
# error "This file can't be compiled directly, include in another source file"
#endif
#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
#define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id)
/* Local identifiers. */
#define pool_create _TPOOL_PREFIX(pool_create)
#define pool_destroy _TPOOL_PREFIX(pool_destroy)
#define pool_clear _TPOOL_PREFIX(pool_clear)
#define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc)
#define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc)
#define pool_elem_free _TPOOL_PREFIX(pool_elem_free)
/* Private identifiers (only for this file, undefine after). */
#define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk)
#define TPoolChunk _TPOOL_PREFIX(TPoolChunk)
#define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree)
#ifndef TPOOL_CHUNK_SIZE
#define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */
#define _TPOOL_CHUNK_SIZE_UNDEF
#endif
#ifndef UNLIKELY
# ifdef __GNUC__
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
# else
# define UNLIKELY(x) (x)
# endif
#endif
#if defined(__GNUC__) || defined(__clang__)
# define MAYBE_UNUSED __attribute__((unused))
#else
# define MAYBE_UNUSED
#endif
struct TPoolChunk {
struct TPoolChunk *prev;
unsigned int size;
unsigned int bufsize;
TPOOL_ALLOC_TYPE buf[0];
};
struct TPoolChunkElemFree {
struct TPoolChunkElemFree *next;
};
struct TPOOL_STRUCT {
/* Always keep at least one chunk (never NULL). */
struct TPoolChunk *chunk;
/* When NULL, allocate a new chunk. */
struct TPoolChunkElemFree *free;
};
/**
* Number of elems to include per #TPoolChunk when no reserved size is passed,
* or we allocate past the reserved number.
*
* \note Optimize number for 64kb allocs.
*/
#define _TPOOL_CHUNK_DEFAULT_NUM \
(((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE))
/* -------------------------------------------------------------------- */
/** \name Internal Memory Management
* \{ */
static struct TPoolChunk *pool_alloc_chunk(
unsigned int tot_elems, struct TPoolChunk *chunk_prev)
{
struct TPoolChunk *chunk = malloc(
sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems));
chunk->prev = chunk_prev;
chunk->bufsize = tot_elems;
chunk->size = 0;
return chunk;
}
static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool)
{
TPOOL_ALLOC_TYPE *elem;
if (pool->free) {
elem = (TPOOL_ALLOC_TYPE *)pool->free;
pool->free = pool->free->next;
}
else {
struct TPoolChunk *chunk = pool->chunk;
if (UNLIKELY(chunk->size == chunk->bufsize)) {
chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk);
}
elem = &chunk->buf[chunk->size++];
}
return elem;
}
MAYBE_UNUSED
static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool)
{
TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool);
memset(elem, 0, sizeof(*elem));
return elem;
}
static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem)
{
struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem;
elem_free->next = pool->free;
pool->free = elem_free;
}
static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve)
{
pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL);
pool->free = NULL;
}
MAYBE_UNUSED
static void pool_clear(struct TPOOL_STRUCT *pool)
{
/* Remove all except the last chunk. */
while (pool->chunk->prev) {
struct TPoolChunk *chunk_prev = pool->chunk->prev;
free(pool->chunk);
pool->chunk = chunk_prev;
}
pool->chunk->size = 0;
pool->free = NULL;
}
static void pool_destroy(struct TPOOL_STRUCT *pool)
{
struct TPoolChunk *chunk = pool->chunk;
do {
struct TPoolChunk *chunk_prev;
chunk_prev = chunk->prev;
free(chunk);
chunk = chunk_prev;
} while (chunk);
pool->chunk = NULL;
pool->free = NULL;
}
/** \} */
#undef _TPOOL_CHUNK_DEFAULT_NUM
#undef _CONCAT_AUX
#undef _CONCAT
#undef _TPOOL_PREFIX
#undef TPoolChunk
#undef TPoolChunkElemFree
#ifdef _TPOOL_CHUNK_SIZE_UNDEF
# undef TPOOL_CHUNK_SIZE
# undef _TPOOL_CHUNK_SIZE_UNDEF
#endif

View File

@@ -0,0 +1,311 @@
/*
* Copyright (c) 2016, Blender Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <COPYRIGHT HOLDER> 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.
*/
/** \file generic_heap.c
* \ingroup curve_fit
*/
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "generic_heap.h"
/* Swap with a temp value. */
#define SWAP_TVAL(tval, a, b) { \
(tval) = (a); \
(a) = (b); \
(b) = (tval); \
} (void)0
#ifdef __GNUC__
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
# define UNLIKELY(x) (x)
#endif
typedef unsigned int uint;
struct HeapNode {
void *ptr;
double value;
uint index;
};
/* heap_* pool allocator. */
#define TPOOL_IMPL_PREFIX heap
#define TPOOL_ALLOC_TYPE HeapNode
#define TPOOL_STRUCT HeapMemPool
#include "generic_alloc_impl.h"
#undef TPOOL_IMPL_PREFIX
#undef TPOOL_ALLOC_TYPE
#undef TPOOL_STRUCT
struct Heap {
uint size;
uint bufsize;
HeapNode **tree;
struct HeapMemPool pool;
};
/** \name Internal Functions
* \{ */
#define HEAP_PARENT(i) (((i) - 1) >> 1)
#define HEAP_LEFT(i) (((i) << 1) + 1)
#define HEAP_RIGHT(i) (((i) << 1) + 2)
/* Compare by value, using index as tie-breaker for deterministic ordering.
* Otherwise equal values would have arbitrary ordering based on the heap's internal state.
* While technically deterministic, this is less stable as minor changes to the heap contents
* can yield different results elsewhere in the heap. */
#define HEAP_COMPARE(a, b) \
(((a)->value < (b)->value) || \
(((a)->value == (b)->value) && ((a)->index < (b)->index)))
#if 0 /* UNUSED */
#define HEAP_EQUALS(a, b) ((a)->value == (b)->value)
#endif
static void heap_swap(Heap *heap, const uint i, const uint j)
{
#if 0
SWAP(uint, heap->tree[i]->index, heap->tree[j]->index);
SWAP(HeapNode *, heap->tree[i], heap->tree[j]);
#else
HeapNode **tree = heap->tree;
union {
uint index;
HeapNode *node;
} tmp;
SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index);
SWAP_TVAL(tmp.node, tree[i], tree[j]);
#endif
}
static void heap_down(Heap *heap, uint i)
{
/* Size won't change in the loop. */
const uint size = heap->size;
while (1) {
const uint l = HEAP_LEFT(i);
const uint r = HEAP_RIGHT(i);
uint smallest;
smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i;
if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) {
smallest = r;
}
if (smallest == i) {
break;
}
heap_swap(heap, i, smallest);
i = smallest;
}
}
static void heap_up(Heap *heap, uint i)
{
while (i > 0) {
const uint p = HEAP_PARENT(i);
if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) {
break;
}
heap_swap(heap, p, i);
i = p;
}
}
/** \} */
/** \name Public Heap API
* \{ */
/* Use when the size of the heap is known in advance. */
Heap *HEAP_new(uint tot_reserve)
{
Heap *heap = malloc(sizeof(Heap));
/* Ensure we have at least one so we can keep doubling it. */
heap->size = 0;
heap->bufsize = tot_reserve ? tot_reserve : 1;
heap->tree = malloc(heap->bufsize * sizeof(HeapNode *));
heap_pool_create(&heap->pool, tot_reserve);
return heap;
}
void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp)
{
if (ptrfreefp) {
uint i;
for (i = 0; i < heap->size; i++) {
ptrfreefp(heap->tree[i]->ptr);
}
}
heap_pool_destroy(&heap->pool);
free(heap->tree);
free(heap);
}
void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp)
{
if (ptrfreefp) {
uint i;
for (i = 0; i < heap->size; i++) {
ptrfreefp(heap->tree[i]->ptr);
}
}
heap->size = 0;
heap_pool_clear(&heap->pool);
}
HeapNode *HEAP_insert(Heap *heap, double value, void *ptr)
{
HeapNode *node;
if (UNLIKELY(heap->size >= heap->bufsize)) {
heap->bufsize *= 2;
heap->tree = realloc(heap->tree, heap->bufsize * sizeof(*heap->tree));
}
node = heap_pool_elem_alloc(&heap->pool);
node->ptr = ptr;
node->value = value;
node->index = heap->size;
heap->tree[node->index] = node;
heap->size++;
heap_up(heap, node->index);
return node;
}
void HEAP_insert_or_update(Heap *heap, HeapNode **node_p, double value, void *ptr)
{
if (*node_p == NULL) {
*node_p = HEAP_insert(heap, value, ptr);
}
else {
HEAP_node_value_update_ptr(heap, *node_p, value, ptr);
}
}
bool HEAP_is_empty(const Heap *heap)
{
return (heap->size == 0);
}
uint HEAP_size(const Heap *heap)
{
return heap->size;
}
HeapNode *HEAP_top(Heap *heap)
{
return heap->tree[0];
}
double HEAP_top_value(const Heap *heap)
{
return heap->tree[0]->value;
}
void *HEAP_popmin(Heap *heap)
{
void *ptr = heap->tree[0]->ptr;
assert(heap->size != 0);
heap_pool_elem_free(&heap->pool, heap->tree[0]);
if (--heap->size) {
heap_swap(heap, 0, heap->size);
heap_down(heap, 0);
}
return ptr;
}
void HEAP_remove(Heap *heap, HeapNode *node)
{
uint i = node->index;
assert(heap->size != 0);
while (i > 0) {
uint p = HEAP_PARENT(i);
heap_swap(heap, p, i);
i = p;
}
HEAP_popmin(heap);
}
void HEAP_node_value_update(Heap *heap, HeapNode *node, double value)
{
assert(heap->size != 0);
if (node->value == value) {
return;
}
node->value = value;
/* Can be called in either order, makes no difference. */
heap_up(heap, node->index);
heap_down(heap, node->index);
}
void HEAP_node_value_update_ptr(Heap *heap, HeapNode *node, double value, void *ptr)
{
node->ptr = ptr;
HEAP_node_value_update(heap, node, value);
}
double HEAP_node_value(const HeapNode *node)
{
return node->value;
}
void *HEAP_node_ptr(HeapNode *node)
{
return node->ptr;
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2016, Blender Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <COPYRIGHT HOLDER> 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 __GENERIC_HEAP_H__
#define __GENERIC_HEAP_H__
/** \file generic_heap.h
* \ingroup curve_fit
*/
struct Heap;
struct HeapNode;
typedef struct Heap Heap;
typedef struct HeapNode HeapNode;
typedef void (*HeapFreeFP)(void *ptr);
Heap *HEAP_new(unsigned int tot_reserve);
bool HEAP_is_empty(const Heap *heap);
void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp);
void *HEAP_node_ptr(HeapNode *node);
void HEAP_remove(Heap *heap, HeapNode *node);
HeapNode *HEAP_insert(Heap *heap, double value, void *ptr);
void HEAP_insert_or_update(Heap *heap, HeapNode **node_p, double value, void *ptr);
void *HEAP_popmin(Heap *heap);
void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp);
unsigned int HEAP_size(const Heap *heap);
HeapNode *HEAP_top(Heap *heap);
double HEAP_top_value(const Heap *heap);
void HEAP_node_value_update(Heap *heap, HeapNode *node, double value);
void HEAP_node_value_update_ptr(Heap *heap, HeapNode *node, double value, void *ptr);
double HEAP_node_value(const HeapNode *node);
#endif /* __GENERIC_HEAP_H__ */