ObjFW
macros.h
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
3  * Jonathan Schleifer <js@webkeks.org>
4  *
5  * All rights reserved.
6  *
7  * This file is part of ObjFW. It may be distributed under the terms of the
8  * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
9  * the packaging of this file.
10  *
11  * Alternatively, it may be distributed under the terms of the GNU General
12  * Public License, either version 2 or 3, which can be found in the file
13  * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
14  * file.
15  */
16 
17 #import "objfw-defs.h"
18 
19 #ifndef __STDC_LIMIT_MACROS
20 # define __STDC_LIMIT_MACROS
21 #endif
22 #ifndef __STDC_CONSTANT_MACROS
23 # define __STDC_CONSTANT_MACROS
24 #endif
25 
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #ifdef OF_OBJFW_RUNTIME
33 # import "runtime.h"
34 #endif
35 #ifdef OF_APPLE_RUNTIME
36 # import <objc/objc.h>
37 # import <objc/runtime.h>
38 # import <objc/message.h>
39 #endif
40 
41 #if defined(__GNUC__)
42 # define restrict __restrict__
43 #elif __STDC_VERSION__ < 199901L
44 # define restrict
45 #endif
46 
47 #if __STDC_VERSION__ >= 201112L && !defined(static_assert)
48 /* C11 compiler, but old libc */
49 # define static_assert _Static_assert
50 #endif
51 
52 #if defined(OF_HAVE__THREAD_LOCAL)
53 # define OF_HAVE_COMPILER_TLS
54 # ifdef OF_HAVE_THREADS_H
55 # include <threads.h>
56 # else
57 # define thread_local _Thread_local
58 # endif
59 #elif defined(OF_HAVE___THREAD)
60 # define OF_HAVE_COMPILER_TLS
61 # define thread_local __thread
62 #endif
63 
64 #ifdef __GNUC__
65 # define OF_INLINE inline __attribute__((__always_inline__))
66 # define OF_LIKELY(cond) (__builtin_expect(!!(cond), 1))
67 # define OF_UNLIKELY(cond) (__builtin_expect(!!(cond), 0))
68 # define OF_CONST_FUNC __attribute__((__const__))
69 # define OF_NO_RETURN_FUNC __attribute__((__noreturn__))
70 #else
71 # define OF_INLINE inline
72 # define OF_LIKELY(cond) cond
73 # define OF_UNLIKELY(cond) cond
74 # define OF_CONST_FUNC
75 # define OF_NO_RETURN_FUNC
76 #endif
77 
78 /* Required to build universal binaries on OS X */
79 #ifdef OF_UNIVERSAL
80 # if __BIG_ENDIAN__
81 # define OF_BIG_ENDIAN
82 # define OF_FLOAT_BIG_ENDIAN
83 # elif !__LITTLE_ENDIAN__
84 # error OF_UNIVERSAL defined, but neither __BIG_ENDIAN__ nor __LITTLE_ENDIAN__!
85 # endif
86 #endif
87 
88 #ifdef OF_BIG_ENDIAN
89 # define OF_BYTE_ORDER_NATIVE OF_BYTE_ORDER_BIG_ENDIAN
90 #else
91 # define OF_BYTE_ORDER_NATIVE OF_BYTE_ORDER_LITTLE_ENDIAN
92 #endif
93 
94 #if __STDC_VERSION__ >= 201112L && defined(OF_HAVE_MAX_ALIGN_T)
95 # define OF_BIGGEST_ALIGNMENT _Alignof(max_align_t)
96 #else
97 # ifdef __BIGGEST_ALIGNMENT__
98 # define OF_BIGGEST_ALIGNMENT __BIGGEST_ALIGNMENT__
99 # else
100 # /* Hopefully no arch needs more than 16 byte alignment */
101 # define OF_BIGGEST_ALIGNMENT 16
102 # endif
103 #endif
104 
105 #ifdef __GNUC__
106 # define __GCC_VERSION__ (__GNUC__ * 100 + __GNUC_MINOR__)
107 #else
108 # define __GCC_VERSION__ 0
109 #endif
110 
111 #if defined(__clang__) || __GCC_VERSION__ >= 406 || defined(OBJC_NEW_PROPERTIES)
112 # define OF_HAVE_PROPERTIES
113 # define OF_HAVE_OPTIONAL_PROTOCOLS
114 # if defined(__clang__) || __GCC_VERSION__ >= 406 || defined(OF_APPLE_RUNTIME)
115 # define OF_HAVE_FAST_ENUMERATION
116 # endif
117 # define OF_HAVE_CLASS_EXTENSIONS
118 # define OF_PRIVATE_CATEGORY
119 #else
120 # define OF_PRIVATE_CATEGORY Private
121 #endif
122 
123 #ifndef __has_feature
124 # define __has_feature(x) 0
125 #endif
126 
127 #ifndef __has_attribute
128 # define __has_attribute(x) 0
129 #endif
130 
131 #if __has_feature(objc_bool)
132 # undef YES
133 # define YES __objc_yes
134 # undef NO
135 # define NO __objc_no
136 # ifndef __cplusplus
137 # undef true
138 # define true ((bool)1)
139 # undef false
140 # define false ((bool)0)
141 # endif
142 #endif
143 
144 #if !__has_feature(objc_instancetype)
145 # define instancetype id
146 #endif
147 
148 #if __has_feature(blocks)
149 # define OF_HAVE_BLOCKS
150 #endif
151 
152 #if __has_feature(objc_arc)
153 # define OF_RETURNS_RETAINED __attribute__((__ns_returns_retained__))
154 # define OF_RETURNS_NOT_RETAINED __attribute__((__ns_returns_not_retained__))
155 # define OF_RETURNS_INNER_POINTER \
156  __attribute__((__objc_returns_inner_pointer__))
157 # define OF_CONSUMED __attribute__((__ns_consumed__))
158 # define OF_WEAK_UNAVAILABLE __attribute__((__objc_arc_weak_unavailable__))
159 #else
160 # define OF_RETURNS_RETAINED
161 # define OF_RETURNS_NOT_RETAINED
162 # define OF_RETURNS_INNER_POINTER
163 # define OF_CONSUMED
164 # define OF_WEAK_UNAVAILABLE
165 # define __unsafe_unretained
166 # define __bridge
167 # define __autoreleasing
168 #endif
169 
170 #if __has_feature(objc_generics)
171 # define OF_HAVE_GENERICS
172 # define OF_GENERIC(...) <__VA_ARGS__>
173 #else
174 # define OF_GENERIC(...)
175 #endif
176 
177 #if __has_feature(nullability)
178 # define OF_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
179 # define OF_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
180 # define OF_NONNULL __nonnull
181 # define OF_NULLABLE __nullable
182 # define OF_NULLABLE_PROPERTY(...) (__VA_ARGS__, nullable)
183 #else
184 # define OF_ASSUME_NONNULL_BEGIN
185 # define OF_ASSUME_NONNULL_END
186 # define OF_NONNULL
187 # define OF_NULLABLE
188 # define OF_NULLABLE_PROPERTY
189 # define nonnull
190 # define nullable
191 #endif
192 
193 #if __has_feature(objc_kindof)
194 # define OF_KINDOF(cls) __kindof cls
195 #else
196 # define OF_KINDOF(cls) id
197 #endif
198 
199 #if defined(__clang__) || __GCC_VERSION__ >= 405
200 # define OF_UNREACHABLE __builtin_unreachable();
201 #else
202 # define OF_UNREACHABLE abort();
203 #endif
204 
205 #if defined(__clang__) || __GCC_VERSION__ >= 406
206 # define OF_SENTINEL __attribute__((__sentinel__))
207 # define OF_NO_RETURN __attribute__((__noreturn__))
208 #else
209 # define OF_SENTINEL
210 # define OF_NO_RETURN
211 #endif
212 
213 #if __has_attribute(__objc_requires_super__)
214 # define OF_REQUIRES_SUPER __attribute__((__objc_requires_super__))
215 #else
216 # define OF_REQUIRES_SUPER
217 #endif
218 
219 #if __has_attribute(__objc_root_class__)
220 # define OF_ROOT_CLASS __attribute__((__objc_root_class__))
221 #else
222 # define OF_ROOT_CLASS
223 #endif
224 
225 #if __has_attribute(__objc_subclassing_restricted__)
226 # define OF_SUBCLASSING_RESTRICTED \
227  __attribute__((__objc_subclassing_restricted__))
228 #else
229 # define OF_SUBCLASSING_RESTRICTED
230 #endif
231 
232 #ifdef __GNUC__
233 # if defined(__x86_64__) || defined(__amd64__)
234 # define OF_X86_64_ASM
235 # elif defined(__i386__)
236 # define OF_X86_ASM
237 # elif defined(__ppc__) || defined(__PPC__)
238 # define OF_PPC_ASM
239 # elif defined(__arm__) || defined(__ARM__)
240 # define OF_ARM_ASM
241 # ifdef __ARM_ARCH_7__
242 # define OF_ARMV7_ASM
243 # endif
244 # ifdef __ARM_ARCH_7A__
245 # define OF_ARMV7_ASM
246 # endif
247 # ifdef __ARM_ARCH_7R__
248 # define OF_ARMV7_ASM
249 # endif
250 # ifdef __ARM_ARCH_7M__
251 # define OF_ARMV7_ASM
252 # endif
253 # ifdef __ARM_ARCH_7EM__
254 # define OF_ARMV7_ASM
255 # endif
256 # ifdef __ARM_ARCH_6__
257 # define OF_ARMV6_ASM
258 # endif
259 # ifdef __ARM_ARCH_6J__
260 # define OF_ARMV6_ASM
261 # endif
262 # ifdef __ARM_ARCH_6K__
263 # define OF_ARMV6_ASM
264 # endif
265 # ifdef __ARM_ARCH_6Z__
266 # define OF_ARMV6_ASM
267 # endif
268 # ifdef __ARM_ARCH_6ZK__
269 # define OF_ARMV6_ASM
270 # endif
271 # ifdef __ARM_ARCH_6T2__
272 # define OF_ARMV6_ASM
273 # endif
274 # ifdef OF_ARMV7_ASM
275 # define OF_ARMV6_ASM
276 # endif
277 # elif defined(__arm64__) || defined(__aarch64__)
278 # define OF_ARM64_ASM
279 # endif
280 #endif
281 
282 #ifdef OF_APPLE_RUNTIME
283 # if defined(__x86_64__) || defined(__i386__) || defined(__ARM64_ARCH_8__) || \
284  defined(__arm__) || defined(__ppc__)
285 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
286 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
287 # endif
288 #else
289 # if defined(__ELF__)
290 # if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) || \
291  defined(__arm__) || defined(__ARM__) || defined(__ppc__) || \
292  defined(__PPC__)
293 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
294 # if __OBJFW_RUNTIME_ABI__ >= 800
295 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
296 # endif
297 # endif
298 # if (defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32) || \
299  (defined(__mips_eabi) && _MIPS_SZPTR == 32)
300 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
301 # if __OBJFW_RUNTIME_ABI__ >= 800
302 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
303 # endif
304 # endif
305 # elif defined(_WIN32)
306 # if defined(__x86_64__) || defined(__i386__)
307 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
308 # if __OBJFW_RUNTIME_ABI__ >= 800
309 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
310 # endif
311 # endif
312 # endif
313 #endif
314 
315 #define OF_RETAIN_COUNT_MAX UINT_MAX
316 #define OF_NOT_FOUND SIZE_MAX
317 
318 #if !defined(_WIN32) && !defined(__DJGPP__)
319 # define OF_PATH_DELIMITER '/'
320 # define OF_PATH_DELIMITER_STRING @"/"
321 # define OF_IS_PATH_DELIMITER(c) (c == '/')
322 #else
323 # define OF_PATH_DELIMITER '\\'
324 # define OF_PATH_DELIMITER_STRING @"\\"
325 # define OF_IS_PATH_DELIMITER(c) (c == '\\' || c == '/')
326 #endif
327 #define OF_PATH_CURRENT_DIRECTORY @"."
328 #define OF_PATH_PARENT_DIRECTORY @".."
329 
330 #define OF_ENSURE(cond) \
331  do { \
332  if (!(cond)) { \
333  fprintf(stderr, "Failed to ensure condition " \
334  "in " __FILE__ ":%d:\n" #cond "\n", \
335  __LINE__); \
336  abort(); \
337  } \
338  } while (0)
339 
340 #define OF_UNRECOGNIZED_SELECTOR of_method_not_found(self, _cmd);
341 #define OF_INVALID_INIT_METHOD \
342  @try { \
343  [self doesNotRecognizeSelector: _cmd]; \
344  } @catch (id e) { \
345  [self release]; \
346  @throw e; \
347  } \
348  \
349  abort();
350 
351 #ifdef __cplusplus
352 extern "C" {
353 #endif
354 extern id objc_getProperty(id, SEL, ptrdiff_t, BOOL);
355 extern void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, signed char);
356 #ifdef __cplusplus
357 }
358 #endif
359 
360 #define OF_IVAR_OFFSET(ivar) ((intptr_t)&ivar - (intptr_t)self)
361 #define OF_GETTER(ivar, atomic) \
362  return objc_getProperty(self, _cmd, OF_IVAR_OFFSET(ivar), atomic);
363 #define OF_SETTER(ivar, value, atomic, copy) \
364  objc_setProperty(self, _cmd, OF_IVAR_OFFSET(ivar), value, atomic, copy);
365 
366 static OF_INLINE uint16_t OF_CONST_FUNC
367 OF_BSWAP16_CONST(uint16_t i)
368 {
369  return (i & UINT16_C(0xFF00)) >> 8 |
370  (i & UINT16_C(0x00FF)) << 8;
371 }
372 
373 static OF_INLINE uint32_t OF_CONST_FUNC
374 OF_BSWAP32_CONST(uint32_t i)
375 {
376  return (i & UINT32_C(0xFF000000)) >> 24 |
377  (i & UINT32_C(0x00FF0000)) >> 8 |
378  (i & UINT32_C(0x0000FF00)) << 8 |
379  (i & UINT32_C(0x000000FF)) << 24;
380 }
381 
382 static OF_INLINE uint64_t OF_CONST_FUNC
383 OF_BSWAP64_CONST(uint64_t i)
384 {
385  return (i & UINT64_C(0xFF00000000000000)) >> 56 |
386  (i & UINT64_C(0x00FF000000000000)) >> 40 |
387  (i & UINT64_C(0x0000FF0000000000)) >> 24 |
388  (i & UINT64_C(0x000000FF00000000)) >> 8 |
389  (i & UINT64_C(0x00000000FF000000)) << 8 |
390  (i & UINT64_C(0x0000000000FF0000)) << 24 |
391  (i & UINT64_C(0x000000000000FF00)) << 40 |
392  (i & UINT64_C(0x00000000000000FF)) << 56;
393 }
394 
395 static OF_INLINE uint16_t OF_CONST_FUNC
396 OF_BSWAP16_NONCONST(uint16_t i)
397 {
398 #if defined(OF_HAVE_BUILTIN_BSWAP16)
399  return __builtin_bswap16(i);
400 #elif defined(OF_X86_64_ASM) || defined(OF_X86_ASM)
401  __asm__ (
402  "xchgb %h0, %b0"
403  : "=Q"(i)
404  : "0"(i)
405  );
406 #elif defined(OF_PPC_ASM)
407  __asm__ (
408  "lhbrx %0, 0, %1"
409  : "=r"(i)
410  : "r"(&i), "m"(i)
411  );
412 #elif defined(OF_ARMV6_ASM)
413  __asm__ (
414  "rev16 %0, %0"
415  : "=r"(i)
416  : "0"(i)
417  );
418 #else
419  i = (i & UINT16_C(0xFF00)) >> 8 |
420  (i & UINT16_C(0x00FF)) << 8;
421 #endif
422  return i;
423 }
424 
425 static OF_INLINE uint32_t OF_CONST_FUNC
426 OF_BSWAP32_NONCONST(uint32_t i)
427 {
428 #if defined(OF_HAVE_BUILTIN_BSWAP32)
429  return __builtin_bswap32(i);
430 #elif defined(OF_X86_64_ASM) || defined(OF_X86_ASM)
431  __asm__ (
432  "bswap %0"
433  : "=q"(i)
434  : "0"(i)
435  );
436 #elif defined(OF_PPC_ASM)
437  __asm__ (
438  "lwbrx %0, 0, %1"
439  : "=r"(i)
440  : "r"(&i), "m"(i)
441  );
442 #elif defined(OF_ARMV6_ASM)
443  __asm__ (
444  "rev %0, %0"
445  : "=r"(i)
446  : "0"(i)
447  );
448 #else
449  i = (i & UINT32_C(0xFF000000)) >> 24 |
450  (i & UINT32_C(0x00FF0000)) >> 8 |
451  (i & UINT32_C(0x0000FF00)) << 8 |
452  (i & UINT32_C(0x000000FF)) << 24;
453 #endif
454  return i;
455 }
456 
457 static OF_INLINE uint64_t OF_CONST_FUNC
458 OF_BSWAP64_NONCONST(uint64_t i)
459 {
460 #if defined(OF_HAVE_BUILTIN_BSWAP64)
461  return __builtin_bswap64(i);
462 #elif defined(OF_X86_64_ASM)
463  __asm__ (
464  "bswap %0"
465  : "=r"(i)
466  : "0"(i)
467  );
468 #elif defined(OF_X86_ASM)
469  __asm__ (
470  "bswap %%eax\n\t"
471  "bswap %%edx\n\t"
472  "xchgl %%eax, %%edx"
473  : "=A"(i)
474  : "0"(i)
475  );
476 #else
477  i = (uint64_t)OF_BSWAP32_NONCONST((uint32_t)(i & 0xFFFFFFFF)) << 32 |
478  OF_BSWAP32_NONCONST((uint32_t)(i >> 32));
479 #endif
480  return i;
481 }
482 
483 #ifdef __GNUC__
484 # define OF_BSWAP16(i) \
485  (__builtin_constant_p(i) ? OF_BSWAP16_CONST(i) : OF_BSWAP16_NONCONST(i))
486 # define OF_BSWAP32(i) \
487  (__builtin_constant_p(i) ? OF_BSWAP32_CONST(i) : OF_BSWAP32_NONCONST(i))
488 # define OF_BSWAP64(i) \
489  (__builtin_constant_p(i) ? OF_BSWAP64_CONST(i) : OF_BSWAP64_NONCONST(i))
490 #else
491 # define OF_BSWAP16(i) OF_BSWAP16_CONST(i)
492 # define OF_BSWAP32(i) OF_BSWAP32_CONST(i)
493 # define OF_BSWAP64(i) OF_BSWAP64_CONST(i)
494 #endif
495 
496 static OF_INLINE float OF_CONST_FUNC
497 OF_BSWAP_FLOAT(float f)
498 {
499  union {
500  float f;
501  uint32_t i;
502  } u;
503 
504  u.f = f;
505  u.i = OF_BSWAP32(u.i);
506 
507  return u.f;
508 }
509 
510 static OF_INLINE double OF_CONST_FUNC
511 OF_BSWAP_DOUBLE(double d)
512 {
513  union {
514  double d;
515  uint64_t i;
516  } u;
517 
518  u.d = d;
519  u.i = OF_BSWAP64(u.i);
520 
521  return u.d;
522 }
523 
524 #ifdef OF_BIG_ENDIAN
525 # define OF_BSWAP16_IF_BE(i) OF_BSWAP16(i)
526 # define OF_BSWAP32_IF_BE(i) OF_BSWAP32(i)
527 # define OF_BSWAP64_IF_BE(i) OF_BSWAP64(i)
528 # define OF_BSWAP16_IF_LE(i) (i)
529 # define OF_BSWAP32_IF_LE(i) (i)
530 # define OF_BSWAP64_IF_LE(i) (i)
531 #else
532 # define OF_BSWAP16_IF_BE(i) (i)
533 # define OF_BSWAP32_IF_BE(i) (i)
534 # define OF_BSWAP64_IF_BE(i) (i)
535 # define OF_BSWAP16_IF_LE(i) OF_BSWAP16(i)
536 # define OF_BSWAP32_IF_LE(i) OF_BSWAP32(i)
537 # define OF_BSWAP64_IF_LE(i) OF_BSWAP64(i)
538 #endif
539 
540 #ifdef OF_FLOAT_BIG_ENDIAN
541 # define OF_BSWAP_FLOAT_IF_BE(i) OF_BSWAP_FLOAT(i)
542 # define OF_BSWAP_DOUBLE_IF_BE(i) OF_BSWAP_DOUBLE(i)
543 # define OF_BSWAP_FLOAT_IF_LE(i) (i)
544 # define OF_BSWAP_DOUBLE_IF_LE(i) (i)
545 #else
546 # define OF_BSWAP_FLOAT_IF_BE(i) (i)
547 # define OF_BSWAP_DOUBLE_IF_BE(i) (i)
548 # define OF_BSWAP_FLOAT_IF_LE(i) OF_BSWAP_FLOAT(i)
549 # define OF_BSWAP_DOUBLE_IF_LE(i) OF_BSWAP_DOUBLE(i)
550 #endif
551 
552 #define OF_ROL(value, bits) \
553  (((bits) % (sizeof(value) * 8)) > 0 \
554  ? ((value) << ((bits) % (sizeof(value) * 8))) | \
555  ((value) >> (sizeof(value) * 8 - ((bits) % (sizeof(value) * 8)))) \
556  : (value))
557 #define OF_ROR(value, bits) \
558  (((bits) % (sizeof(value) * 8)) > 0 \
559  ? ((value) >> ((bits) % (sizeof(value) * 8))) | \
560  ((value) << (sizeof(value) * 8 - ((bits) % (sizeof(value) * 8)))) \
561  : (value))
562 
563 #define OF_ROUND_UP_POW2(pow2, value) (((value) + (pow2) - 1) & ~((pow2) - 1))
564 
565 #define OF_HASH_INIT(hash) hash = of_hash_seed;
566 #define OF_HASH_ADD(hash, byte) \
567  { \
568  hash += (uint8_t)(byte); \
569  hash += (hash << 10); \
570  hash ^= (hash >> 6); \
571  }
572 #define OF_HASH_FINALIZE(hash) \
573  { \
574  hash += (hash << 3); \
575  hash ^= (hash >> 11); \
576  hash += (hash << 15); \
577  }
578 #define OF_HASH_ADD_HASH(hash, other) \
579  { \
580  uint32_t otherCopy = other; \
581  OF_HASH_ADD(hash, (otherCopy >> 24) & 0xFF); \
582  OF_HASH_ADD(hash, (otherCopy >> 16) & 0xFF); \
583  OF_HASH_ADD(hash, (otherCopy >> 8) & 0xFF); \
584  OF_HASH_ADD(hash, otherCopy & 0xFF); \
585  }
586 
587 static OF_INLINE char*
588 of_strdup(const char *string)
589 {
590  char *copy;
591  size_t length = strlen(string);
592 
593  if ((copy = (char*)malloc(length + 1)) == NULL)
594  return NULL;
595 
596  memcpy(copy, string, length + 1);
597 
598  return copy;
599 }