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