1 /*@ Code of the basic infrastructure (POD types, macros etc.) and functions.
2 *@ And main documentation entry point, as below.
3 *@ - Reacts upon su_HAVE_DEBUG, su_HAVE_DEVEL, and NDEBUG.
4 *@ The latter is a precondition for su_HAVE_INLINE; dependent upon compiler
5 *@ __OPTIMIZE__ (and __OPTIMIZE_SIZE__) may be looked at in addition, then.
6 *@ su_HAVE_DEVEL is meant as a possibility to enable test paths with
8 *@ - Some macros require su_FILE to be defined to a literal.
9 *@ - Define su_MASTER to inject what is to be injected once; for example,
10 *@ it enables su_M*CTA() compile time assertions.
12 * Copyright (c) 2001 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
13 * SPDX-License-Identifier: ISC
15 * Permission to use, copy, modify, and/or distribute this software for any
16 * purpose with or without fee is hereby granted, provided that the above
17 * copyright notice and this permission notice appear in all copies.
19 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
20 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
22 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
25 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 #include <su/config.h>
34 # define su_HAVE_DEBUG
35 # define su_HAVE_DEVEL
36 # define su_HAVE_DOCSTRINGS
37 # define su_HAVE_MEM_BAG_AUTO
38 # define su_HAVE_MEM_BAG_LOFI
39 # define su_HAVE_MEM_CANARIES_DISABLE
47 #define su_OS_CYGWIN 0
48 #define su_OS_DARWIN 0
49 #define su_OS_DRAGONFLY 0
51 #define su_OS_FREEBSD 0
55 #define su_OS_NETBSD 0
56 #define su_OS_OPENBSD 0
57 #define su_OS_SOLARIS 0
62 #elif defined __CYGWIN__
64 # define su_OS_CYGWIN 1
65 #elif defined DARWIN || defined _DARWIN
67 # define su_OS_DARWIN 1
68 #elif defined __DragonFly__
69 # undef su_OS_DRAGONFLY
70 # define su_OS_DRAGONFLY 1
74 #elif defined __FreeBSD__
76 # define su_OS_FREEBSD 1
77 #elif defined __linux__ || defined __linux
79 # define su_OS_LINUX 1
82 # define su_OS_MINIX 1
83 #elif defined __MSDOS__
85 # define su_OS_MSDOS 1
86 #elif defined __NetBSD__
88 # define su_OS_NETBSD 1
89 #elif defined __OpenBSD__
91 # define su_OS_OPENBSD 1
92 #elif defined __solaris__ || defined __sun
93 # if defined __SVR4 || defined __svr4__
95 # define su_OS_SOLARIS 1
98 # define su_OS_SUNOS 1
105 # define su_C_DECL_BEGIN
106 # define su_C_DECL_END
108 # define su_S(T,I) ((T)(I))
109 # define su_R(T,I) ((T)(I))
110 # define su_C(T,I) ((T)su_R(su_up,I))
111 # define su_NIL ((void*)0)
114 # define su_C_DECL_BEGIN extern "C" {
115 # define su_C_DECL_END }
117 # define su_NSPC_BEGIN(X) namespace X {
118 # define su_NSPC_END(X) }
119 # define su_NSPC_USE(X) using namespace X;
120 # define su_NSPC(X) X::
122 # define su_NSPC_BEGIN(X) /**/
123 # define su_NSPC_END(X) /**/
124 # define su_NSPC_USE(X) /**/
125 # define su_NSPC(X) /**/::
127 /* Disable copy-construction and assignment of class */
128 # define su_CLASS_NO_COPY(C) private:C(C const &);C &operator=(C const &);
129 /* If C++ class inherits from a C class, and the C class "return self", we
130 * have to waste a return register even if self==this */
131 # define su_SELFTHIS_RET(X) /* return *(X); */ X; return *this
132 /* C++ only allows those at the declaration, not the definition */
139 /* This is for the declarator only */
140 # if __cplusplus +0 < 201103L
143 # define su_OVRX override
146 # define su_S(T,I) static_cast<T>(I)
147 # define su_R(T,I) reinterpret_cast<T>(I)
148 # define su_C(T,I) const_cast<T>(I)
150 #endif /* __cplusplus */
152 /* "su_EXPORT myfun()", "class su_EXPORT myclass" */
153 #if su_OS_WIN32 || su_OS_WIN64
154 # define su_EXPORT __declspec((dllexport))
155 # define su_EXPORT_DATA __declspec((dllexport))
156 # define su_IMPORT __declspec((dllimport))
157 # define su_IMPORT_DATA __declspec((dllimport))
159 # define su_EXPORT /*extern*/
160 # define su_EXPORT_DATA extern
161 # define su_IMPORT /*extern*/
162 # define su_IMPORT_DATA extern
164 /* Compile-Time-Assert
165 * Problem is that some compilers warn on unused local typedefs, so add
166 * a special local CTA to overcome this */
167 #if (!su_C_LANG && __cplusplus +0 >= 201103L) || defined DOXYGEN
168 # define su_CTA(T,M) static_assert(T, M)
169 # define su_LCTA(T,M) static_assert(T, M)
170 #elif 0 /* unusable! */ && \
171 defined __STDC_VERSION__ && __STDC_VERSION__ +0 >= 201112L
172 # define su_CTA(T,M) _Static_assert(T, M)
173 # define su_LCTA(T,M) _Static_assert(T, M)
175 # define su_CTA(T,M) su__CTA_1(T, su_FILE, __LINE__)
176 # define su_LCTA(T,M) su__LCTA_1(T, su_FILE, __LINE__)
177 # define su__CTA_1(T,F,L) su__CTA_2(T, F, L)
178 # define su__CTA_2(T,F,L) \
179 typedef char ASSERTION_failed_file_ ## F ## _line_ ## L[(T) ? 1 : -1]
180 # define su__LCTA_1(T,F,L) su__LCTA_2(T, F, L)
181 # define su__LCTA_2(T,F,L) \
183 typedef char ASSERT_failed_file_ ## F ## _line_ ## L[(T) ? 1 : -1];\
184 ASSERT_failed_file_ ## F ## _line_ ## L __i_am_unused__;\
185 su_UNUSED(__i_am_unused__);\
188 #define su_CTAV(T) su_CTA(T, "Unexpected value of constant")
189 #define su_LCTAV(T) su_LCTA(T, "Unexpected value of constant")
191 # define su_MCTA(T,M) su_CTA(T, M);
193 # define su_MCTA(T,M)
197 #define su_CC_CLANG 0
198 #define su_CC_VCHECK_CLANG(X,Y) 0
200 #define su_CC_VCHECK_GCC(X,Y) 0
202 #define su_CC_VCHECK_PCC(X,Y) 0
203 #define su_CC_SUNPROC 0
204 #define su_CC_VCHECK_SUNPROC(X,Y) 0
205 #define su_CC_TINYC 0
206 #define su_CC_VCHECK_TINYC(X,Y) 0
209 # undef su_CC_VCHECK_CLANG
210 # define su_CC_CLANG 1
211 # define su_CC_VCHECK_CLANG(X,Y) \
212 (__clang_major__ +0 > (X) || \
213 (__clang_major__ +0 == (X) && __clang_minor__ +0 >= (Y)))
214 # define su_CC_EXTEN __extension__
215 # define su_CC_PACKED __attribute__((packed))
216 # if !defined su_CC_BOM &&\
217 defined __BYTE_ORDER__ && defined __ORDER_LITTLE_ENDIAN__ &&\
218 defined __ORDER_BIG_ENDIAN
219 # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
220 # define su_CC_BOM su_CC_BOM_LITTLE
221 # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
222 # define su_CC_BOM su_CC_BOM_BIG
224 # error Unsupported __BYTE_ORDER__
227 /* __GNUC__ after some other Unix compilers which also define __GNUC__ */
228 #elif defined __PCC__ /* __clang__ */
230 # undef su_CC_VCHECK_PCC
232 # define su_CC_VCHECK_PCC(X,Y) \
233 (__PCC__ +0 > (X) || (__PCC__ +0 == (X) && __PCC_MINOR__ +0 >= (Y)))
234 # define su_CC_EXTEN __extension__
235 # define su_CC_PACKED __attribute__((packed))
236 # if !defined su_CC_BOM &&\
237 defined __BYTE_ORDER__ && defined __ORDER_LITTLE_ENDIAN__ &&\
238 defined __ORDER_BIG_ENDIAN
239 # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
240 # define su_CC_BOM su_CC_BOM_LITTLE
241 # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
242 # define su_CC_BOM su_CC_BOM_BIG
244 # error Unsupported __BYTE_ORDER__
247 #elif defined __SUNPRO_C /* __PCC__ */
248 # undef su_CC_SUNPROC
249 # define su_CC_SUNPROC 1
250 # define su_CC_PACKED TODO: PACKED attribute not supported for SunPro C
251 #elif defined __TINYC__ /* __SUNPRO_C */
253 # define su_CC_TINYC 1
254 # define su_CC_EXTEN /* __extension__ (ignored) */
255 # define su_CC_PACKED __attribute__((packed))
256 #elif defined __GNUC__ /* __TINYC__ */
258 # undef su_CC_VCHECK_GCC
260 # define su_CC_VCHECK_GCC(X,Y) \
261 (__GNUC__ +0 > (X) || (__GNUC__ +0 == (X) && __GNUC_MINOR__ +0 >= (Y)))
262 # define su_CC_EXTEN __extension__
263 # define su_CC_PACKED __attribute__((packed))
264 # if !defined su_CC_BOM &&\
265 defined __BYTE_ORDER__ && defined __ORDER_LITTLE_ENDIAN__ &&\
266 defined __ORDER_BIG_ENDIAN
267 # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
268 # define su_CC_BOM su_CC_BOM_LITTLE
269 # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
270 # define su_CC_BOM su_CC_BOM_BIG
272 # error Unsupported __BYTE_ORDER__
275 #elif !defined su_CC_IGNORE_UNKNOWN
276 # error SU: This compiler is not yet supported.
277 # error SU: To continue with your CFLAGS etc., define su_CC_IGNORE_UNKNOWN.
278 # error SU: It may be necessary to define su_CC_PACKED to a statement that
279 # error SU: enables structure packing; it may not be a #pragma, but a _Pragma
285 # define su_CC_PACKED TODO: PACKED attribute not supported for this compiler
287 #if defined su_CC_BOM || defined DOXYGEN
291 # define su_CC_BOM_LITTLE 1234
292 # define su_CC_BOM_BIG 4321
294 #if !defined su_CC_UZ_TYPE && defined __SIZE_TYPE__
295 # define su_CC_UZ_TYPE __SIZE_TYPE__
298 #if defined __STDC_VERSION__ && __STDC_VERSION__ +0 >= 199901L
299 # define su_FUN __func__
300 #elif su_CC_CLANG || su_CC_VCHECK_GCC(3, 4) || su_CC_PCC || su_CC_TINYC
301 # define su_FUN __extension__ __FUNCTION__
303 # define su_FUN su_empty /* Something that is not a literal */
306 #define su_HAVE_INLINE
309 # define su_INLINE inline
310 # define su_SINLINE inline
311 # elif su_CC_CLANG || su_CC_GCC || su_CC_PCC
312 # if defined __STDC_VERSION__ && __STDC_VERSION__ +0 >= 199901l
313 # if !defined NDEBUG || !defined __OPTIMIZE__
314 # define su_INLINE static inline
315 # define su_SINLINE static inline
317 /* clang does not like inline with <-O2 */
318 # define su_INLINE inline __attribute__((always_inline))
319 # define su_SINLINE static inline __attribute__((always_inline))
322 # if su_CC_VCHECK_GCC(3, 1)
323 # define su_INLINE static __inline __attribute__((always_inline))
324 # define su_SINLINE static __inline __attribute__((always_inline))
326 # define su_INLINE static __inline
327 # define su_SINLINE static __inline
331 # define su_INLINE static /* TODO __attribute__((unused)) alike? */
332 # define su_SINLINE static /* TODO __attribute__((unused)) alike? */
333 # undef su_HAVE_INLINE
336 # define su_INLINE inline
337 # define su_SINLINE static inline
340 # undef su_HAVE_INLINE
342 #if defined __predict_true && defined __predict_false
343 # define su_LIKELY(X) __predict_true((X) != 0)
344 # define su_UNLIKELY(X) __predict_false((X) != 0)
345 #elif su_CC_CLANG || su_CC_VCHECK_GCC(2, 96) || su_CC_PCC || su_CC_TINYC
346 # define su_LIKELY(X) __builtin_expect((X) != 0, 1)
347 # define su_UNLIKELY(X) __builtin_expect((X) != 0, 0)
349 # define su_LIKELY(X) ((X) != 0)
350 # define su_UNLIKELY(X) ((X) != 0)
353 /* SUPPORT MACROS+ {{{ */
354 /* USECASE_XY_DISABLED for tagging unused files:
355 * git rm `git grep ^su_USECASE_MX_DISABLED` */
357 # define su_USECASE_MX_DISABLED This file is not a (valid) compilation unit
359 #ifndef su_USECASE_MX_DISABLED
360 # define su_USECASE_MX_DISABLED
362 /* Basic support macros, with side effects */
363 #define su_ABS(A) ((A) < 0 ? -(A) : (A))
364 #define su_CLIP(X,A,B) (((X) <= (A)) ? (A) : (((X) >= (B)) ? (B) : (X)))
365 #define su_IS_POW2(X) ((((X) - 1) & (X)) == 0)
366 #define su_MAX(A,B) ((A) < (B) ? (B) : (A))
367 #define su_MIN(A,B) ((A) < (B) ? (A) : (B))
368 #define su_ROUND_DOWN(X,BASE) (((X) / (BASE)) * (BASE))
369 #define su_ROUND_DOWN2(X,BASE) ((X) & (~((BASE) - 1)))
370 #define su_ROUND_UP(X,BASE) ((((X) + ((BASE) - 1)) / (BASE)) * (BASE))
371 #define su_ROUND_UP2(X,BASE) (((X) + ((BASE) - 1)) & (~((BASE) - 1)))
372 /* Alignment. Note: su_uz POW2 asserted in POD section below! */
373 /* Commented out: "_Alignof() applied to an expression is a GNU extension" */
374 #if 0 && defined __STDC_VERSION__ && __STDC_VERSION__ +0 >= 201112L
375 # include <stdalign.h>
376 # define su_ALIGNOF(X) _Alignof(X)
378 # define su_ALIGNOF(X) su_ROUND_UP2(sizeof(X), su__ZAL_L)
380 #define su_P_ALIGN(DTYPE,OTYPE,MEM) \
382 su_IS_POW2(su_ALIGNOF(OTYPE))\
383 ? su_ROUND_UP2(su_R(su_up,MEM), su_ALIGNOF(OTYPE))\
384 : su_ROUND_UP(su_R(su_up,MEM), su_ALIGNOF(OTYPE)))
385 /* Roundup/align an integer; Note: POW2 asserted in POD section below! */
386 #define su_Z_ALIGN_OVER(X) su_ROUND_UP2(su_S(su_uz,X), 2 * su__ZAL_L)
387 #define su_Z_ALIGN(X) su_ROUND_UP2(su_S(su_uz,X), su__ZAL_L)
388 #define su_Z_ALIGN_PZ(X) su_ROUND_UP2(su_S(su_uz,X), su__ZAL_S)
389 /* (These are below MCTA()d to be of equal size[, however].)
390 * _L must adhere to the minimum aligned claimed in the \mainpage */
391 # define su__ZAL_S su_MAX(sizeof(su_uz), sizeof(void*))
392 # define su__ZAL_L su_MAX(su__ZAL_S, sizeof(su_u64))/* XXX FP,128bit */
393 /* Variants of ASSERT */
394 #if defined NDEBUG || defined DOXYGEN
395 # define su_ASSERT_INJ(X)
396 # define su_ASSERT_INJOR(X,Y) Y
397 # define su_ASSERT_NB(X) ((void)0)
398 # define su_ASSERT(X) do{}while(0)
399 # define su_ASSERT_LOC(X,FNAME,LNNO) do{}while(0)
400 # define su_ASSERT_EXEC(X,S) do{}while(0)
401 # define su_ASSERT_EXEC_LOC(X,S,FNAME,LNNO) do{}while(0)
402 # define su_ASSERT_JUMP(X,L) do{}while(0)
403 # define su_ASSERT_JUMP_LOC(X,L,FNAME,LNNO) do{}while(0)
404 # define su_ASSERT_RET(X,Y) do{}while(0)
405 # define su_ASSERT_RET_LOC(X,Y,FNAME,LNNO) do{}while(0)
406 # define su_ASSERT_RET_VOID(X) do{}while(0)
407 # define su_ASSERT_RET_VOID_LOC(X,Y,FNAME,LNNO) do{}while(0)
408 # define su_ASSERT_NYD_EXEC(X,Y) do{}while(0)
409 # define su_ASSERT_NYD_EXEC_LOC(X,FNAME,LNNO) do{}while(0)
410 # define su_ASSERT_NYD(X) do{}while(0)
411 # define su_ASSERT_NYD_LOC(X,FNAME,LNNO) do{}while(0)
413 # define su_ASSERT_INJ(X) X
414 # define su_ASSERT_INJOR(X,Y) X
415 # define su_ASSERT_NB(X) \
416 su_R(void,((X) ? su_TRU1 \
417 : su_assert(su_STRING(X), __FILE__, __LINE__, su_FUN, su_TRU1), su_FAL0))
418 # define su_ASSERT(X) su_ASSERT_LOC(X, __FILE__, __LINE__)
419 # define su_ASSERT_LOC(X,FNAME,LNNO) \
421 su_assert(su_STRING(X), FNAME, LNNO, su_FUN, su_TRU1);\
423 # define su_ASSERT_EXEC(X,S) su_ASSERT_EXEC_LOC(X, S, __FILE__, __LINE__)
424 # define su_ASSERT_EXEC_LOC(X,S,FNAME,LNNO) \
426 su_assert(su_STRING(X), FNAME, LNNO, su_FUN, su_FAL0);\
429 # define su_ASSERT_JUMP(X,L) su_ASSERT_JUMP_LOC(X, L, __FILE__, __LINE__)
430 # define su_ASSERT_JUMP_LOC(X,L,FNAME,LNNO) \
432 su_assert(su_STRING(X), FNAME, LNNO, su_FUN, su_FAL0);\
435 # define su_ASSERT_RET(X,Y) su_ASSERT_RET_LOC(X, Y, __FILE__, __LINE__)
436 # define su_ASSERT_RET_LOC(X,Y,FNAME,LNNO) \
438 su_assert(su_STRING(X), FNAME, LNNO, su_FUN, su_FAL0);\
441 # define su_ASSERT_RET_VOID(X) su_ASSERT_RET_VOID_LOC(X, __FILE__, __LINE__)
442 # define su_ASSERT_RET_VOID_LOC(X,FNAME,LNNO) \
444 su_assert(su_STRING(X), FNAME, LNNO, su_FUN, su_FAL0);\
447 # define su_ASSERT_NYD_EXEC(X,Y) \
448 su_ASSERT_NYD_EXEC_LOC(X, Y, __FILE__, __LINE__)
449 # define su_ASSERT_NYD_EXEC_LOC(X,Y,FNAME,LNNO) \
451 su_assert(su_STRING(X), FNAME, LNNO, su_FUN, su_FAL0);\
452 Y; goto su_NYD_OU_LABEL;\
454 # define su_ASSERT_NYD(X) su_ASSERT_NYD_LOC(X, __FILE__, __LINE__)
455 # define su_ASSERT_NYD_LOC(X,FNAME,LNNO) \
457 su_assert(su_STRING(X), FNAME, LNNO, su_FUN, su_FAL0);\
458 goto su_NYD_OU_LABEL;\
460 #endif /* defined NDEBUG || defined DOXYGEN */
461 #define su_BITENUM_IS(X,Y) X
462 #define su_BITENUM_MASK(LO,HI) (((1u << ((HI) + 1)) - 1) & ~((1u << (LO)) - 1))
464 /* Debug injections */
465 #if defined su_HAVE_DEBUG && !defined NDEBUG
468 # define su_DBGOR(X,Y) X
471 # define su_NDBG(X) X
472 # define su_DBGOR(X,Y) Y
474 /* Debug file location arguments. (For an usage example see su/mem.h.) */
475 #if defined su_HAVE_DEVEL || defined su_HAVE_DEBUG
476 # define su_HAVE_DBG_LOC_ARGS
477 # define su_DBG_LOC_ARGS_FILE su__dbg_loc_args_file
478 # define su_DBG_LOC_ARGS_LINE su__dbg_loc_args_line
479 # define su_DBG_LOC_ARGS_DECL_SOLE \
480 char const *su_DBG_LOC_ARGS_FILE, su_u32 su_DBG_LOC_ARGS_LINE
481 # define su_DBG_LOC_ARGS_DECL , su_DBG_LOC_ARGS_DECL_SOLE
482 # define su_DBG_LOC_ARGS_INJ_SOLE __FILE__, __LINE__
483 # define su_DBG_LOC_ARGS_INJ , su_DBG_LOC_ARGS_INJ_SOLE
484 # define su_DBG_LOC_ARGS_USE_SOLE su_DBG_LOC_ARGS_FILE, su_DBG_LOC_ARGS_LINE
485 # define su_DBG_LOC_ARGS_USE , su_DBG_LOC_ARGS_USE_SOLE
486 # define su_DBG_LOC_ARGS_ORUSE su_DBG_LOC_ARGS_FILE, su_DBG_LOC_ARGS_LINE
487 # define su_DBG_LOC_ARGS_UNUSED() \
489 su_UNUSED(su_DBG_LOC_ARGS_FILE);\
490 su_UNUSED(su_DBG_LOC_ARGS_LINE);\
493 # define su_DBG_LOC_ARGS_FILE "unused"
494 # define su_DBG_LOC_ARGS_LINE 0
496 # define su_DBG_LOC_ARGS_DECL_SOLE
497 # define su_DBG_LOC_ARGS_DECL
498 # define su_DBG_LOC_ARGS_INJ_SOLE
499 # define su_DBG_LOC_ARGS_INJ
500 # define su_DBG_LOC_ARGS_USE_SOLE
501 # define su_DBG_LOC_ARGS_USE
502 # define su_DBG_LOC_ARGS_ORUSE su_DBG_LOC_ARGS_FILE, su_DBG_LOC_ARGS_LINE
503 # define su_DBG_LOC_ARGS_UNUSED() do{}while(0)
504 #endif /* su_HAVE_DEVEL || su_HAVE_DEBUG */
505 /* Development injections */
506 #if defined su_HAVE_DEVEL || defined su_HAVE_DEBUG /* Not: !defined NDEBUG) */\
510 # define su_DVLOR(X,Y) X
513 # define su_NDVL(X) X
514 # define su_DVLOR(X,Y) Y
516 #define su_EMPTY_FILE() typedef int su_CONCAT(su_notempty_shall_b_, su_FILE);
518 #if (su_C_LANG && defined __STDC_VERSION__ && \
519 __STDC_VERSION__ +0 >= 199901L) || defined DOXYGEN
520 # define su_FIELD_INITN(N) .N =
521 # define su_FIELD_INITI(I) [I] =
523 # define su_FIELD_INITN(N)
524 # define su_FIELD_INITI(I)
526 /* XXX offsetof+: clang,pcc check faked! */
527 #if su_CC_VCHECK_CLANG(5, 0) || su_CC_VCHECK_GCC(4, 1) ||\
528 su_CC_VCHECK_PCC(1, 2) || defined DOXYGEN
529 # define su_FIELD_OFFSETOF(T,F) __builtin_offsetof(T, F)
531 # define su_FIELD_OFFSETOF(T,F) \
532 su_S(su_uz,su_S(su_up,&(su_R(T *,0x1)->F)) - 1)
534 #define su_FIELD_RANGEOF(T,S,E) \
535 (su_FIELD_OFFSETOF(T, E) - su_FIELD_OFFSETOF(T, S))
536 #define su_FIELD_SIZEOF(T,F) sizeof(su_S(T *,su_NIL)->F)
537 /* Multithread injections */
543 #define su_NELEM(A) (sizeof(A) / sizeof((A)[0]))
544 #define su_NYD_OU_LABEL su__nydou
545 #define su_P2UZ(X) su_S(su_uz,(su_up)(X))
546 #define su_PCMP(A,C,B) (su_R(su_up,A) C su_R(su_up,B))
554 * __STDC_VERSION__ is ISO C99, so also use __STDC__, which should work */
555 #if defined __STDC__ || defined __STDC_VERSION__ || su_C_LANG || \
557 # define su_STRING(X) #X
558 # define su_XSTRING(X) su_STRING(X)
559 # define su_CONCAT(S1,S2) su__CONCAT_1(S1, S2)
560 # define su__CONCAT_1(S1,S2) S1 ## S2
562 # define su_STRING(X) "X"
563 # define su_XSTRING STRING
564 # define su_CONCAT(S1,S2) S1/* will no work out though */S2
566 #if su_C_LANG || defined DOXYGEN
567 # define su_UCMP(T,A,C,B) (su_S(su_ ## u ## T,A) C su_S(su_ ## u ## T,B))
569 # define su_UCMP(T,A,C,B) \
570 (su_S(su_NSPC(su) u ## T,A) C su_S(su_NSPC(su) u ## T,B))
572 #define su_UNCONST(T,P) su_R(T,su_R(su_up,su_S(void const*,P)))
573 #define su_UNVOLATILE(T,P) su_R(T,su_R(su_up,su_S(void volatile*,P)))
574 #define su_UNALIGN(T,P) su_R(T,su_R(su_up,P))
575 #define su_UNXXX(T,C,P) su_R(T,su_R(su_up,su_S(C,P)))
576 /* Avoid "may be used uninitialized" warnings */
577 #if (defined NDEBUG && !(defined su_HAVE_DEBUG || defined su_HAVE_DEVEL)) || \
579 # define su_UNINIT(N,V) su_S(void,0)
580 # define su_UNINIT_DECL(V)
582 # define su_UNINIT(N,V) N = V
583 # define su_UNINIT_DECL(V) = V
585 #define su_UNUSED(X) ((void)(X))
586 #if (su_C_LANG && defined __STDC_VERSION__ && \
587 __STDC_VERSION__ +0 >= 199901L) || defined DOXYGEN
588 # define su_VFIELD_SIZE(X)
589 # define su_VSTRUCT_SIZEOF(T,F) sizeof(T)
591 # define su_VFIELD_SIZE(X) \
592 ((X) == 0 ? sizeof(su_uz) \
593 : (su_S(su_sz,X) < 0 ? sizeof(su_uz) - su_ABS(X) : su_S(su_uz,X)))
594 # define su_VSTRUCT_SIZEOF(T,F) (sizeof(T) - su_FIELD_SIZEOF(T, F))
596 /* SUPPORT MACROS+ }}} */
597 /* We are ready to start using our own style */
598 #ifndef su_CC_SIZE_TYPE
599 # include <sys/types.h> /* TODO create config time script, */
601 #include <inttypes.h> /* TODO query infos and drop */
602 #include <limits.h> /* TODO those includes! */
604 #include <su/code-in.h>
606 /* POD TYPE SUPPORT TODO maybe configure-time, from a su/config.h?! {{{ */
607 /* TODO Note: the PRI* series will go away once we have FormatCtx! */
608 /* First some shorter aliases for "normal" integers */
609 typedef unsigned long su_ul
;
610 typedef unsigned int su_ui
;
611 typedef unsigned short su_us
;
612 typedef unsigned char su_uc
;
613 typedef signed long su_sl
;
614 typedef signed int su_si
;
615 typedef signed short su_ss
;
616 typedef signed char su_sc
;
617 #if defined UINT8_MAX || defined DOXYGEN
618 # define su_U8_MAX UINT8_MAX
619 # define su_S8_MIN INT8_MIN
620 # define su_S8_MAX INT8_MAX
621 typedef uint8_t su_u8
;
622 typedef int8_t su_s8
;
623 #elif UCHAR_MAX != 255
624 # error UCHAR_MAX must be 255
626 # define su_U8_MAX UCHAR_MAX
627 # define su_S8_MIN CHAR_MIN
628 # define su_S8_MAX CHAR_MAX
629 typedef unsigned char su_u8
;
630 typedef signed char su_s8
;
632 #if !defined PRIu8 || !defined PRId8
638 #if defined UINT16_MAX || defined DOXYGEN
639 # define su_U16_MAX UINT16_MAX
640 # define su_S16_MIN INT16_MIN
641 # define su_S16_MAX INT16_MAX
642 typedef uint16_t su_u16
;
643 typedef int16_t su_s16
;
644 #elif USHRT_MAX != 0xFFFFu
645 # error USHRT_MAX must be 0xFFFF
647 # define su_U16_MAX USHRT_MAX
648 # define su_S16_MIN SHRT_MIN
649 # define su_S16_MAX SHRT_MAX
650 typedef unsigned short su_u16
;
651 typedef signed short su_s16
;
653 #if !defined PRIu16 || !defined PRId16
656 # if su_U16_MAX == UINT_MAX
664 #if defined UINT32_MAX || defined DOXYGEN
665 # define su_U32_MAX UINT32_MAX
666 # define su_S32_MIN INT32_MIN
667 # define su_S32_MAX INT32_MAX
668 typedef uint32_t su_u32
;
669 typedef int32_t su_s32
;
670 #elif ULONG_MAX == 0xFFFFFFFFu
671 # define su_U32_MAX ULONG_MAX
672 # define su_S32_MIN LONG_MIN
673 # define su_S32_MAX LONG_MAX
674 typedef unsigned long int su_u32
;
675 typedef signed long int su_s32
;
676 #elif UINT_MAX != 0xFFFFFFFFu
677 # error UINT_MAX must be 0xFFFFFFFF
679 # define su_U32_MAX UINT_MAX
680 # define su_S32_MIN INT_MIN
681 # define su_S32_MAX INT_MAX
682 typedef unsigned int su_u32
;
683 typedef signed int su_s32
;
685 #if !defined PRIu32 || !defined PRId32
688 # if su_U32_MAX == ULONG_MAX
696 #if defined UINT64_MAX || defined DOXYGEN
697 # define su_U64_MAX UINT64_MAX
698 # define su_S64_MIN INT64_MIN
699 # define su_S64_MAX INT64_MAX
700 # define su_S64_C(C) INT64_C(C)
701 # define su_U64_C(C) UINT64_C(C)
702 typedef uint64_t su_u64
;
703 typedef int64_t su_s64
;
704 #elif ULONG_MAX <= 0xFFFFFFFFu
705 # if !defined ULLONG_MAX
706 # error We need a 64 bit integer
708 # define su_U64_MAX ULLONG_MAX
709 # define su_S64_MIN LLONG_MIN
710 # define su_S64_MAX LLONG_MAX
711 # define su_S64_C(C) su_CONCAT(C, ll)
712 # define su_U64_C(C) su_CONCAT(C, ull)
713 su_CC_EXTEN
typedef unsigned long long su_u64
;
714 su_CC_EXTEN
typedef signed long long su_s64
;
717 # define su_U64_MAX ULONG_MAX
718 # define su_S64_MIN LONG_MIN
719 # define su_S64_MAX LONG_MAX
720 # define su_S64_C(C) su_CONCAT(C, l)
721 # define su_U64_C(C) su_CONCAT(C, ul)
722 typedef unsigned long su_u64
;
723 typedef signed long su_s64
;
725 #if !defined PRIu64 || !defined PRId64 || !defined PRIX64 || !defined PRIo64
730 # if defined ULLONG_MAX && su_U64_MAX == ULLONG_MAX
731 # define PRIu64 "llu"
732 # define PRId64 "lld"
733 # define PRIX64 "llX"
734 # define PRIo64 "llo"
742 /* (So that we can use UCMP() for size_t comparison, too) */
743 #ifdef su_CC_SIZE_TYPE
744 typedef su_CC_SIZE_TYPE su_uz
;
746 typedef size_t su_uz
;
750 #if (defined __STDC_VERSION__ && __STDC_VERSION__ +0 >= 199901L) ||\
754 # define su_UZ_MAX SIZE_MAX
755 #elif defined SIZE_MAX
756 /* UnixWare has size_t as unsigned as required but uses a signed limit
757 * constant (which is thus false!) */
758 # if SIZE_MAX == su_U64_MAX || SIZE_MAX == su_S64_MAX
759 # define PRIuZ PRIu64
760 # define PRIdZ PRId64
761 MCTA(sizeof(size_t) == sizeof(u64
),
762 "Format string mismatch, compile with ISO C99 compiler (-std=c99)!")
763 # elif SIZE_MAX == su_U32_MAX || SIZE_MAX == su_S32_MAX
764 # define PRIuZ PRIu32
765 # define PRIdZ PRId32
766 MCTA(sizeof(size_t) == sizeof(u32
),
767 "Format string mismatch, compile with ISO C99 compiler (-std=c99)!")
769 # error SIZE_MAX is neither su_U64_MAX nor su_U32_MAX (please report this)
771 # define su_UZ_MAX SIZE_MAX
773 #if !defined PRIuZ && !defined DOXYGEN
776 MCTA(sizeof(size_t) == sizeof(unsigned long),
777 "Format string mismatch, compile with ISO C99 compiler (-std=c99)!")
779 /* The signed equivalence is not really compliant to the standard */
780 #if su_UZ_MAX == su_U32_MAX || su_UZ_MAX == su_S32_MAX || defined DOXYGEN
781 # define su_SZ_MIN su_S32_MIN
782 # define su_SZ_MAX su_S32_MAX
783 # define su_UZ_BITS 32u
786 # define su_6432(X,Y) Y
787 typedef su_s32 su_sz
;
788 #elif su_UZ_MAX == su_U64_MAX
789 # define su_SZ_MIN su_S64_MIN
790 # define su_SZ_MAX su_S64_MAX
791 # define su_UZ_BITS 64u
794 # define su_6432(X,Y) X
795 typedef su_s64 su_sz
;
797 # error I cannot handle this maximum value of size_t
799 MCTA(sizeof(su_uz
) == sizeof(void*),
800 "SU cannot handle sizeof(su_uz) != sizeof(void*)")
801 /* Regardless of P2UZ provide this one; only use it rarely */
802 #if defined UINTPTR_MAX || defined DOXYGEN
803 typedef uintptr_t su_up
;
804 typedef intptr_t su_sp
;
820 typedef su_s8 su_boole
;
821 /* POD TYPE SUPPORT }}} */
822 /* BASIC TYPE TRAITS {{{ */
824 /* plus PTF typedefs */
825 typedef void *(*su_new_fun
)(u32 estate
);
826 typedef void *(*su_clone_fun
)(void const *t
, u32 estate
);
827 typedef void (*su_delete_fun
)(void *self
);
828 typedef void *(*su_assign_fun
)(void *self
, void const *t
, u32 estate
);
829 typedef su_sz (*su_compare_fun
)(void const *a
, void const *b
);
830 typedef su_uz (*su_hash_fun
)(void const *self
);
831 /* Needs to be binary compatible with \c{su::{toolbox,type_toolbox<T>}}! */
833 su_clone_fun tb_clone
;
834 su_delete_fun tb_delete
;
835 su_assign_fun tb_assign
;
836 su_compare_fun tb_compare
;
839 /* Use C-style casts, not and ever su_R()! */
840 #define su_TOOLBOX_I9R(CLONE,DELETE,ASSIGN,COMPARE,HASH) \
842 su_FIELD_INITN(tb_clone) (su_clone_fun)(CLONE),\
843 su_FIELD_INITN(tb_delete) (su_delete_fun)(DELETE),\
844 su_FIELD_INITN(tb_assign) (su_assign_fun)(ASSIGN),\
845 su_FIELD_INITN(tb_compare) (su_compare_fun)(COMPARE),\
846 su_FIELD_INITN(tb_hash) (su_hash_fun)(HASH)\
848 /* BASIC TYPE TRAITS }}} */
849 /* BASIC C INTERFACE (SYMBOLS) {{{ */
850 #define su_BOM 0xFEFFu
851 /* su_state.. machinery: first byte: global log instance.. */
863 su__LOG_MAX
= su_LOG_DEBUG
,
865 su__LOG_MASK
= (1u << su__LOG_SHIFT
) - 1
867 MCTA(1u<<su__LOG_SHIFT
> su__LOG_MAX
, "Bit ranges may not overlap")
869 su_LOG_F_CORE
= 1u<<(su__LOG_SHIFT
+0)
871 enum su_state_log_flags
{
872 su_STATE_LOG_SHOW_LEVEL
= 1u<<4,
873 su_STATE_LOG_SHOW_PID
= 1u<<5
875 /* ..second byte: hardening errors.. */
876 enum su_state_err_type
{
877 su_STATE_ERR_NOMEM
= 1u<<8,
878 su_STATE_ERR_OVERFLOW
= 1u<<9
880 enum su_state_err_flags
{
881 su_STATE_ERR_TYPE_MASK
= su_STATE_ERR_NOMEM
| su_STATE_ERR_OVERFLOW
,
882 su_STATE_ERR_PASS
= su_STATE_ERR_TYPE_MASK
,
883 su_STATE_ERR_NOPASS
= 1u<<12,
884 su_STATE_ERR_NOERRNO
= 1u<<13,
885 su_STATE_ERR_NIL_IS_VALID_OBJECT
= 1u<<14,
886 su_STATE_ERR_NILISVALO
= su_STATE_ERR_NIL_IS_VALID_OBJECT
,
887 su_STATE_ERR_MASK
= su_STATE_ERR_TYPE_MASK
|
888 su_STATE_ERR_PASS
| su_STATE_ERR_NOPASS
| su_STATE_ERR_NOERRNO
|
889 su_STATE_ERR_NIL_IS_VALID_OBJECT
891 /* ..third byte: misc flags */
894 su_STATE_DEBUG
= 1u<<16,
895 su_STATE_VERBOSE
= 1u<<17,
896 su_STATE_REPRODUCIBLE
= 1u<<18
898 enum su__state_flags
{
899 /* enum su_log_level is first "member" */
900 su__STATE_LOG_MASK
= 0x0Fu
,
901 su__STATE_D_V
= su_STATE_DEBUG
| su_STATE_VERBOSE
,
902 /* What is not allowed in the global state machine */
903 su__STATE_GLOBAL_MASK
= 0x00FFFFFFu
& ~(su__STATE_LOG_MASK
|
904 (su_STATE_ERR_MASK
& ~su_STATE_ERR_TYPE_MASK
))
906 MCTA(S(uz
,su_LOG_DEBUG
) <= S(uz
,su__STATE_LOG_MASK
),
907 "Bit ranges may not overlap")
908 MCTA((S(uz
,su_STATE_ERR_MASK
) & ~0xFF00) == 0, "Bits excess documented bounds")
913 su__GLOCK_MAX
= su__GLOCK_LOG
921 su__ERR_NUMBER_ENUM_C
922 # undef su__ERR_NUMBER_ENUM_C
929 /* Known endianness bom versions, see su_bom_little, su_bom_big */
930 EXPORT_DATA
union su__bom_union
const su__bom_little
;
931 EXPORT_DATA
union su__bom_union
const su__bom_big
;
932 /* (Not yet) Internal enum su_state_* bit carrier */
933 EXPORT_DATA uz su__state
;
934 EXPORT_DATA u16
const su_bom
;
935 #define su_bom_little su__bom_little.bu_val
936 #define su_bom_big su__bom_big.bu_val
937 #if defined su_CC_BOM || defined DOXYGEN
938 # define su_BOM_IS_BIG() (su_CC_BOM == su_CC_BOM_BIG)
939 # define su_BOM_IS_LITTLE() (su_CC_BOM == su_CC_BOM_LITTLE)
941 # define su_BOM_IS_BIG() (su_bom == su_bom_big)
942 # define su_BOM_IS_LITTLE() (su_bom == su_bom_little)
944 EXPORT_DATA
char const su_empty
[1];
945 EXPORT_DATA
char const su_reproducible_build
[];
946 EXPORT_DATA
char const *su_program
;
949 EXPORT
void su__glock(enum su__glock_type gt
);
950 EXPORT
void su__gunlock(enum su__glock_type gt
);
952 INLINE u32
su_state_get(void){
953 return (su__state
& su__STATE_GLOBAL_MASK
);
955 INLINE boole
su_state_has(uz flags
){
956 flags
&= su__STATE_GLOBAL_MASK
;
957 return ((su__state
& flags
) == flags
);
959 INLINE
void su_state_set(uz flags
){
960 MT( su__glock(su__GLOCK_STATE
); )
961 su__state
|= flags
& su__STATE_GLOBAL_MASK
;
962 MT( su__gunlock(su__GLOCK_STATE
); )
964 INLINE
void su_state_clear(uz flags
){
965 MT( su__glock(su__GLOCK_STATE
); )
966 su__state
&= ~(flags
& su__STATE_GLOBAL_MASK
);
967 MT( su__gunlock(su__GLOCK_STATE
); )
969 EXPORT s32
su_state_err(enum su_state_err_type err
, uz state
,
970 char const *msg_or_nil
);
971 EXPORT s32
su_err_no(void);
972 EXPORT s32
su_err_set_no(s32 eno
);
973 EXPORT
char const *su_err_doc(s32 eno
);
974 EXPORT
char const *su_err_name(s32 eno
);
975 EXPORT s32
su_err_from_name(char const *name
);
976 EXPORT s32
su_err_no_via_errno(void);
977 INLINE
enum su_log_level
su_log_get_level(void){
978 return S(enum su_log_level
,su__state
& su__STATE_LOG_MASK
);
980 INLINE
void su_log_set_level(enum su_log_level nlvl
){
982 /*MT( su__glock(su__GLOCK_STATE); )*/
983 lvl
= S(uz
,nlvl
) & su__STATE_LOG_MASK
;
984 su__state
= (su__state
& su__STATE_GLOBAL_MASK
) | lvl
;
985 /*MT( su__gunlock(su__GLOCK_STATE); )*/
987 INLINE boole
su_log_would_write(enum su_log_level lvl
){
988 return ((S(u32
,lvl
) & su__LOG_MASK
) <= (su__state
& su__STATE_LOG_MASK
) ||
989 (su__state
& su__STATE_D_V
));
991 EXPORT
void su_log_write(BITENUM_IS(u32
,su_log_level
) lvl
,
992 char const *fmt
, ...);
993 EXPORT
void su_log_vwrite(BITENUM_IS(u32
,su_log_level
) lvl
,
994 char const *fmt
, void *vp
);
995 EXPORT
void su_perr(char const *msg
, s32 eno_or_0
);
996 INLINE
void su_log_lock(void){
997 MT( su__glock(su__GLOCK_LOG
); )
999 INLINE
void su_log_unlock(void){
1000 MT( su__gunlock(su__GLOCK_LOG
); )
1002 #if !defined su_ASSERT_EXPAND_NOTHING || defined DOXYGEN
1003 EXPORT
void su_assert(char const *expr
, char const *file
, u32 line
,
1004 char const *fun
, boole crash
);
1006 # define su_assert(EXPR,FILE,LINE,FUN,CRASH)
1009 EXPORT
void su_nyd_set_disabled(boole disabled
);
1010 EXPORT
void su_nyd_reset_level(u32 nlvl
);
1011 EXPORT
void su_nyd_chirp(u8 act
, char const *file
, u32 line
, char const *fun
);
1012 EXPORT
void su_nyd_dump(void (*ptf
)(up cookie
, char const *buf
, uz blen
),
1015 /* BASIC C INTERFACE (SYMBOLS) }}} */
1017 #include <su/code-ou.h>
1018 /* MORE DOXYGEN TOP GROUPS {{{ */
1019 /* MORE DOXYGEN TOP GROUPS }}} */
1020 #endif /* !su_CODE_H */