damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

paligned_alloc.h (5920B)


      1 #ifndef PALIGNED_ALLOC_H
      2 
      3 #ifdef __cplusplus
      4 extern "C" {
      5 #endif
      6 
      7 /*
      8  * NOTE: MSVC in general has no aligned alloc function that is
      9  * compatible with free and it is not trivial to implement a version
     10  * which is. Therefore, to remain portable, end user code needs to
     11  * use `aligned_free` which is not part of C11 but defined in this header.
     12  *
     13  * glibc only provides aligned_alloc when _ISOC11_SOURCE is defined, but
     14  * MingW does not support aligned_alloc despite of this, it uses the
     15  * the _aligned_malloc as MSVC.
     16  *
     17  * The same issue is present on some Unix systems not providing
     18  * posix_memalign.
     19  *
     20  * Note that clang and gcc with -std=c11 or -std=c99 will not define
     21  * _POSIX_C_SOURCE and thus posix_memalign cannot be detected but
     22  * aligned_alloc is not necessarily available either. We assume
     23  * that clang always has posix_memalign although it is not strictly
     24  * correct. For gcc, use -std=gnu99 or -std=gnu11 or don't use -std in
     25  * order to enable posix_memalign, or live with the fallback until using
     26  * a system where glibc has a version that supports aligned_alloc.
     27  *
     28  * For C11 compliant compilers and compilers with posix_memalign,
     29  * it is valid to use free instead of aligned_free with the above
     30  * caveats.
     31  */
     32 
     33 #include <stdlib.h>
     34 
     35 /*
     36  * Define this to see which version is used so the fallback is not
     37  * enganged unnecessarily:
     38  *
     39  * #define PORTABLE_DEBUG_ALIGNED_ALLOC
     40  */
     41 
     42 #if 0
     43 #define PORTABLE_DEBUG_ALIGNED_ALLOC
     44 #endif
     45 
     46 #if !defined(PORTABLE_C11_ALIGNED_ALLOC)
     47 
     48 /*
     49  * PORTABLE_C11_ALIGNED_ALLOC = 1
     50  * indicates that the system has builtin aligned_alloc
     51  * If it doesn't, the section after detection provides an implemention.
     52  */
     53 #if defined (__MINGW32__)
     54 /* MingW does not provide aligned_alloc despite defining _ISOC11_SOURCE */
     55 #define PORTABLE_C11_ALIGNED_ALLOC 0
     56 #elif defined (_ISOC11_SOURCE) 
     57 /* glibc aligned_alloc detection, but MingW is not truthful */
     58 #define PORTABLE_C11_ALIGNED_ALLOC 1
     59 #elif defined (__GLIBC__)
     60 /* aligned_alloc is not available in glibc just because __STDC_VERSION__ >= 201112L. */
     61 #define PORTABLE_C11_ALIGNED_ALLOC 0
     62 #elif defined (__clang__)
     63 #define PORTABLE_C11_ALIGNED_ALLOC 0
     64 #elif defined (__APPLE__)
     65 #define PORTABLE_C11_ALIGNED_ALLOC 0
     66 #elif defined(__IBMC__)
     67 #define PORTABLE_C11_ALIGNED_ALLOC 0
     68 #elif (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
     69 #define PORTABLE_C11_ALIGNED_ALLOC 1
     70 #else
     71 #define PORTABLE_C11_ALIGNED_ALLOC 0
     72 #endif
     73 
     74 #endif /* PORTABLE_C11_ALIGNED_ALLOC */
     75 
     76 /* https://linux.die.net/man/3/posix_memalign */
     77 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_GNU_SOURCE)
     78 #define PORTABLE_POSIX_MEMALIGN 1
     79 #endif
     80 
     81 /* https://forum.kde.org/viewtopic.php?p=66274 */
     82 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_XOPEN_SOURCE)
     83 #if _XOPEN_SOURCE >= 600
     84 #define PORTABLE_POSIX_MEMALIGN 1
     85 #endif
     86 #endif
     87 
     88 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_POSIX_C_SOURCE)
     89 #if _POSIX_C_SOURCE >= 200112L
     90 #define PORTABLE_POSIX_MEMALIGN 1
     91 #endif
     92 #endif
     93 
     94 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(__clang__)
     95 #define PORTABLE_POSIX_MEMALIGN 1
     96 #endif
     97 
     98 #if !defined(PORTABLE_POSIX_MEMALIGN)
     99 #define PORTABLE_POSIX_MEMALIGN 0
    100 #endif
    101 
    102 /* https://forum.kde.org/viewtopic.php?p=66274 */
    103 #if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
    104 /* C11 or newer */
    105 #include <stdalign.h>
    106 #endif
    107 
    108 /* C11 or newer */
    109 #if !defined(aligned_alloc) && !defined(__aligned_alloc_is_defined)
    110 
    111 #if PORTABLE_C11_ALIGNED_ALLOC
    112 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
    113 #error "DEBUG: C11_ALIGNED_ALLOC configured"
    114 #endif
    115 #elif defined(_MSC_VER) || defined(__MINGW32__)
    116 
    117 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
    118 #error "DEBUG: Windows _aligned_malloc configured"
    119 #endif
    120 
    121 /* Aligned _aligned_malloc is not compatible with free. */
    122 #define aligned_alloc(alignment, size) _aligned_malloc(size, alignment)
    123 #define aligned_free(p) _aligned_free(p)
    124 #define __aligned_alloc_is_defined 1
    125 #define __aligned_free_is_defined 1
    126 
    127 #elif PORTABLE_POSIX_MEMALIGN
    128 
    129 #if defined(__GNUC__)
    130 #if !defined(__GNUCC__)
    131 extern int posix_memalign (void **, size_t, size_t);
    132 #elif __GNUCC__ < 5
    133 extern int posix_memalign (void **, size_t, size_t);
    134 #endif
    135 #endif
    136 
    137 static inline void *__portable_aligned_alloc(size_t alignment, size_t size)
    138 {
    139     int err;
    140     void *p = 0;
    141 
    142     if (alignment < sizeof(void *)) {
    143         alignment = sizeof(void *);
    144     }
    145     err = posix_memalign(&p, alignment, size);
    146     if (err && p) {
    147         free(p);
    148         p = 0;
    149     }
    150     return p;
    151 }
    152 
    153 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
    154 #error "DEBUG: POSIX_MEMALIGN configured"
    155 #endif
    156 
    157 #define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size)
    158 #define aligned_free(p) free(p)
    159 #define __aligned_alloc_is_defined 1
    160 #define __aligned_free_is_defined 1
    161 
    162 #else
    163 
    164 static inline void *__portable_aligned_alloc(size_t alignment, size_t size)
    165 {
    166     char *raw;
    167     void *buf;
    168     size_t total_size = (size + alignment - 1 + sizeof(void *));
    169 
    170     if (alignment < sizeof(void *)) {
    171         alignment = sizeof(void *);
    172     }
    173     raw = (char *)(size_t)malloc(total_size);
    174     buf = raw + alignment - 1 + sizeof(void *);
    175     buf = (void *)(((size_t)buf) & ~(alignment - 1));
    176     ((void **)buf)[-1] = raw;
    177     return buf;
    178 }
    179 
    180 static inline void __portable_aligned_free(void *p)
    181 {
    182     char *raw;
    183     
    184     if (p) {
    185         raw = (char*)((void **)p)[-1];
    186         free(raw);
    187     }
    188 }
    189 
    190 #define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size)
    191 #define aligned_free(p) __portable_aligned_free(p)
    192 #define __aligned_alloc_is_defined 1
    193 #define __aligned_free_is_defined 1
    194 
    195 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
    196 #error "DEBUG: aligned_alloc malloc fallback configured"
    197 #endif
    198 
    199 #endif
    200 
    201 #endif /* aligned_alloc */
    202 
    203 #if !defined(aligned_free) && !defined(__aligned_free_is_defined)
    204 #define aligned_free(p) free(p)
    205 #define __aligned_free_is_defined 1
    206 #endif
    207 
    208 #ifdef __cplusplus
    209 }
    210 #endif
    211 
    212 #endif /* PALIGNED_ALLOC_H */