1 // SPDX-License-Identifier: MPL-2.0
2 // Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
3 #pragma once
4 #include <assert.h>
5 #include <ctype.h>
6 #include <limits.h>
7 #include <math.h>
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include <test.h>
16
17 #include "compiler.h"
18
19 #define ARR_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
20
21 #ifdef __FAST_MATH__
22 #warning Use of -ffast-math can cause rendering error or artifacts, \
23 therefore it is not recommended.
24 #endif
25
26 #ifdef __clang__
27 __attribute__((optnone))
28 #else
29 __attribute__((optimize("-fno-fast-math")))
30 #endif
31 static inline bool
safe_isnan(double a)32 safe_isnan(double a) {
33 return __builtin_isnan(a);
34 }
35
36 /// Same as assert(false), but make sure we abort _even in release builds_.
37 /// Silence compiler warning caused by release builds making some code paths reachable.
38 #define BUG() \
39 do { \
40 assert(false); \
41 abort(); \
42 } while (0)
43 #define CHECK_EXPR(...) ((void)0)
44 /// Same as assert, but evaluates the expression even in release builds
45 #define CHECK(expr) \
46 do { \
47 auto _ = (expr); \
48 /* make sure the original expression appears in the assertion message */ \
49 assert((CHECK_EXPR(expr), _)); \
50 (void)_; \
51 } while (0)
52
53 /// Asserts that var is within [lower, upper]. Silence compiler warning about expressions
54 /// being always true or false.
55 #define ASSERT_IN_RANGE(var, lower, upper) \
56 do { \
57 auto __tmp attr_unused = (var); \
58 _Pragma("GCC diagnostic push"); \
59 _Pragma("GCC diagnostic ignored \"-Wtype-limits\""); \
60 assert(__tmp >= lower); \
61 assert(__tmp <= upper); \
62 _Pragma("GCC diagnostic pop"); \
63 } while (0)
64
65 /// Asserts that var >= lower. Silence compiler warning about expressions
66 /// being always true or false.
67 #define ASSERT_GEQ(var, lower) \
68 do { \
69 auto __tmp attr_unused = (var); \
70 _Pragma("GCC diagnostic push"); \
71 _Pragma("GCC diagnostic ignored \"-Wtype-limits\""); \
72 assert(__tmp >= lower); \
73 _Pragma("GCC diagnostic pop"); \
74 } while (0)
75
76 // Some macros for checked cast
77 // Note these macros are not complete, as in, they won't work for every integer types. But
78 // they are good enough for our use cases.
79
80 #define to_int_checked(val) \
81 ({ \
82 int64_t tmp = (val); \
83 ASSERT_IN_RANGE(tmp, INT_MIN, INT_MAX); \
84 (int)tmp; \
85 })
86
87 #define to_char_checked(val) \
88 ({ \
89 int64_t tmp = (val); \
90 ASSERT_IN_RANGE(tmp, CHAR_MIN, CHAR_MAX); \
91 (char)tmp; \
92 })
93
94 #define to_u16_checked(val) \
95 ({ \
96 auto tmp = (val); \
97 ASSERT_IN_RANGE(tmp, 0, UINT16_MAX); \
98 (uint16_t) tmp; \
99 })
100
101 #define to_i16_checked(val) \
102 ({ \
103 int64_t tmp = (val); \
104 ASSERT_IN_RANGE(tmp, INT16_MIN, INT16_MAX); \
105 (int16_t) tmp; \
106 })
107
108 #define to_u32_checked(val) \
109 ({ \
110 auto tmp = (val); \
111 int64_t max attr_unused = UINT32_MAX; /* silence clang tautological \
112 comparison warning*/ \
113 ASSERT_IN_RANGE(tmp, 0, max); \
114 (uint32_t) tmp; \
115 })
116 /**
117 * Normalize an int value to a specific range.
118 *
119 * @param i int value to normalize
120 * @param min minimal value
121 * @param max maximum value
122 * @return normalized value
123 */
normalize_i_range(int i,int min,int max)124 static inline int attr_const normalize_i_range(int i, int min, int max) {
125 if (i > max)
126 return max;
127 if (i < min)
128 return min;
129 return i;
130 }
131
132 #define min2(a, b) ((a) > (b) ? (b) : (a))
133 #define max2(a, b) ((a) > (b) ? (a) : (b))
134
135 /// clamp `val` into interval [min, max]
136 #define clamp(val, min, max) max2(min2(val, max), min)
137
138 /**
139 * Normalize a double value to a specific range.
140 *
141 * @param d double value to normalize
142 * @param min minimal value
143 * @param max maximum value
144 * @return normalized value
145 */
normalize_d_range(double d,double min,double max)146 static inline double attr_const normalize_d_range(double d, double min, double max) {
147 if (d > max)
148 return max;
149 if (d < min)
150 return min;
151 return d;
152 }
153
154 /**
155 * Normalize a double value to 0.\ 0 - 1.\ 0.
156 *
157 * @param d double value to normalize
158 * @return normalized value
159 */
normalize_d(double d)160 static inline double attr_const normalize_d(double d) {
161 return normalize_d_range(d, 0.0, 1.0);
162 }
163
164 attr_noret void
165 report_allocation_failure(const char *func, const char *file, unsigned int line);
166
167 /**
168 * @brief Quit if the passed-in pointer is empty.
169 */
170 static inline void *
allocchk_(const char * func_name,const char * file,unsigned int line,void * ptr)171 allocchk_(const char *func_name, const char *file, unsigned int line, void *ptr) {
172 if (unlikely(!ptr)) {
173 report_allocation_failure(func_name, file, line);
174 }
175 return ptr;
176 }
177
178 /// @brief Wrapper of allocchk_().
179 #define allocchk(ptr) allocchk_(__func__, __FILE__, __LINE__, ptr)
180
181 /// @brief Wrapper of malloc().
182 #define cmalloc(type) ((type *)allocchk(malloc(sizeof(type))))
183
184 /// @brief Wrapper of malloc() that takes a size
185 #define cvalloc(size) allocchk(malloc(size))
186
187 /// @brief Wrapper of calloc().
188 #define ccalloc(nmemb, type) \
189 ({ \
190 auto tmp = (nmemb); \
191 ASSERT_GEQ(tmp, 0); \
192 ((type *)allocchk(calloc((size_t)tmp, sizeof(type)))); \
193 })
194
195 /// @brief Wrapper of ealloc().
196 #define crealloc(ptr, nmemb) \
197 ({ \
198 auto tmp = (nmemb); \
199 ASSERT_GEQ(tmp, 0); \
200 ((__typeof__(ptr))allocchk(realloc((ptr), (size_t)tmp * sizeof(*(ptr))))); \
201 })
202
203 /// RC_TYPE generates a reference counted type from `type`
204 ///
205 /// parameters:
206 /// name = the generated type will be called `name`_t.
207 /// ctor = the constructor of `type`, will be called when
208 /// a value of `type` is created. should take one
209 /// argument of `type *`.
210 /// dtor = the destructor. will be called when all reference
211 /// is gone. has same signature as ctor
212 /// Q = function qualifier. this is the qualifier that
213 /// will be put before generated functions
214 //
215 /// functions generated:
216 /// `name`_new: create a new reference counted object of `type`
217 /// `name`_ref: increment the reference counter, return a
218 /// reference to the object
219 /// `name`_unref: decrement the reference counter. take a `type **`
220 /// because it needs to nullify the reference.
221 #define RC_TYPE(type, name, ctor, dtor, Q) \
222 typedef struct { \
223 type inner; \
224 int ref_count; \
225 } name##_internal_t; \
226 typedef type name##_t; \
227 Q type *name##_new(void) { \
228 name##_internal_t *ret = cmalloc(name##_internal_t); \
229 ctor((type *)ret); \
230 ret->ref_count = 1; \
231 return (type *)ret; \
232 } \
233 Q type *name##_ref(type *a) { \
234 __auto_type b = (name##_internal_t *)a; \
235 b->ref_count++; \
236 return a; \
237 } \
238 Q void name##_unref(type **a) { \
239 __auto_type b = (name##_internal_t *)*a; \
240 if (!b) \
241 return; \
242 b->ref_count--; \
243 if (!b->ref_count) { \
244 dtor((type *)b); \
245 free(b); \
246 } \
247 *a = NULL; \
248 }
249
250 /// Generate prototypes for functions generated by RC_TYPE
251 #define RC_TYPE_PROTO(type, name) \
252 typedef type name##_t; \
253 type *name##_new(void); \
254 void name##_ref(type *a); \
255 void name##_unref(type **a);
256
257 ///
258 /// Calculates next closest power of two of 32bit integer n
259 /// ref: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
260 ///
261 int next_power_of_two(int n);
262
263 // vim: set noet sw=8 ts=8 :
264