2018-10-04 05:14:51 +08:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
2018-09-30 06:37:15 +08:00
|
|
|
#pragma once
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
2018-11-03 22:02:58 +08:00
|
|
|
#include <stdbool.h>
|
2018-11-02 21:57:19 +08:00
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#ifdef __FAST_MATH__
|
|
|
|
#warning Use of -ffast-math can cause rendering error or artifacts, \
|
|
|
|
therefore it is not recommended.
|
|
|
|
#endif
|
|
|
|
|
2018-11-03 22:02:58 +08:00
|
|
|
#ifdef __clang__
|
|
|
|
__attribute__((optnone))
|
|
|
|
#else
|
2018-11-02 21:57:19 +08:00
|
|
|
__attribute__((optimize("-fno-fast-math")))
|
2018-11-03 22:02:58 +08:00
|
|
|
#endif
|
2018-11-02 21:57:19 +08:00
|
|
|
static inline bool safe_isnan(double a) {
|
|
|
|
return isnan(a);
|
|
|
|
}
|
2018-10-21 09:58:37 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Normalize an int value to a specific range.
|
|
|
|
*
|
|
|
|
* @param i int value to normalize
|
|
|
|
* @param min minimal value
|
|
|
|
* @param max maximum value
|
|
|
|
* @return normalized value
|
|
|
|
*/
|
|
|
|
static inline int __attribute__((const))
|
|
|
|
normalize_i_range(int i, int min, int max) {
|
|
|
|
if (i > max) return max;
|
|
|
|
if (i < min) return min;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Select the larger integer of two.
|
|
|
|
*/
|
|
|
|
static inline int __attribute__((const))
|
|
|
|
max_i(int a, int b) {
|
|
|
|
return (a > b ? a : b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Select the smaller integer of two.
|
|
|
|
*/
|
|
|
|
static inline int __attribute__((const))
|
|
|
|
min_i(int a, int b) {
|
|
|
|
return (a > b ? b : a);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Select the larger long integer of two.
|
|
|
|
*/
|
|
|
|
static inline long __attribute__((const))
|
|
|
|
max_l(long a, long b) {
|
|
|
|
return (a > b ? a : b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Select the smaller long integer of two.
|
|
|
|
*/
|
|
|
|
static inline long __attribute__((const))
|
|
|
|
min_l(long a, long b) {
|
|
|
|
return (a > b ? b : a);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Normalize a double value to a specific range.
|
|
|
|
*
|
|
|
|
* @param d double value to normalize
|
|
|
|
* @param min minimal value
|
|
|
|
* @param max maximum value
|
|
|
|
* @return normalized value
|
|
|
|
*/
|
|
|
|
static inline double __attribute__((const))
|
|
|
|
normalize_d_range(double d, double min, double max) {
|
|
|
|
if (d > max) return max;
|
|
|
|
if (d < min) return min;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Normalize a double value to 0.\ 0 - 1.\ 0.
|
|
|
|
*
|
|
|
|
* @param d double value to normalize
|
|
|
|
* @return normalized value
|
|
|
|
*/
|
|
|
|
static inline double __attribute__((const))
|
|
|
|
normalize_d(double d) {
|
|
|
|
return normalize_d_range(d, 0.0, 1.0);
|
|
|
|
}
|
|
|
|
|
2018-09-30 06:37:15 +08:00
|
|
|
static inline const char *
|
|
|
|
skip_space_const(const char *src) {
|
|
|
|
if (!src)
|
|
|
|
return NULL;
|
|
|
|
while (*src && isspace(*src))
|
|
|
|
src++;
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline char *
|
|
|
|
skip_space_mut(char *src) {
|
|
|
|
if (!src)
|
|
|
|
return NULL;
|
|
|
|
while (*src && isspace(*src))
|
|
|
|
src++;
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define skip_space(x) _Generic((x), \
|
|
|
|
char *: skip_space_mut, \
|
|
|
|
const char *: skip_space_const \
|
|
|
|
)(x)
|
|
|
|
|
|
|
|
/// RC_TYPE generates a reference counted type from `type`
|
|
|
|
///
|
|
|
|
/// parameters:
|
|
|
|
/// name = the generated type will be called `name`_t.
|
|
|
|
/// ctor = the constructor of `type`, will be called when
|
|
|
|
/// a value of `type` is created. should take one
|
|
|
|
/// argument of `type *`.
|
|
|
|
/// dtor = the destructor. will be called when all reference
|
|
|
|
/// is gone. has same signature as ctor
|
|
|
|
/// Q = function qualifier. this is the qualifier that
|
|
|
|
/// will be put before generated functions
|
|
|
|
//
|
|
|
|
/// functions generated:
|
|
|
|
/// `name`_new: create a new reference counted object of `type`
|
|
|
|
/// `name`_ref: increment the reference counter, return a
|
|
|
|
/// reference to the object
|
|
|
|
/// `name`_unref: decrement the reference counter. take a `type **`
|
|
|
|
/// because it needs to nullify the reference.
|
|
|
|
#define RC_TYPE(type, name, ctor, dtor, Q) \
|
|
|
|
typedef struct { \
|
|
|
|
type inner; \
|
|
|
|
int ref_count; \
|
|
|
|
} name##_internal_t; \
|
|
|
|
typedef type name##_t; \
|
|
|
|
Q type *name##_new(void) { \
|
|
|
|
name##_internal_t *ret = malloc(sizeof(name##_internal_t)); \
|
|
|
|
ctor((type *)ret); \
|
|
|
|
ret->ref_count = 1; \
|
|
|
|
return (type *)ret; \
|
|
|
|
} \
|
|
|
|
Q type *name##_ref(type *a) { \
|
|
|
|
__auto_type b = (name##_internal_t *)a; \
|
|
|
|
b->ref_count++; \
|
|
|
|
return a; \
|
|
|
|
} \
|
|
|
|
Q void name##_unref(type **a) { \
|
|
|
|
__auto_type b = (name##_internal_t *)*a; \
|
|
|
|
if (!b) \
|
|
|
|
return; \
|
|
|
|
b->ref_count--; \
|
|
|
|
if (!b->ref_count) {\
|
|
|
|
dtor((type *)b); \
|
|
|
|
free(b); \
|
|
|
|
} \
|
|
|
|
*a = NULL; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate prototypes for functions generated by RC_TYPE
|
|
|
|
#define RC_TYPE_PROTO(type, name) \
|
|
|
|
typedef type name##_t; \
|
|
|
|
type *name##_new(void); \
|
|
|
|
void name##_ref(type *a); \
|
|
|
|
void name##_unref(type **a);
|