2026-05-28 14:25:01 +02:00
|
|
|
#ifndef KARLOS_UTIL_H
|
|
|
|
|
#define KARLOS_UTIL_H
|
|
|
|
|
|
2026-05-30 02:13:25 +02:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
2026-05-28 14:25:01 +02:00
|
|
|
#define LIST_INSERT_TAIL(head, elem) do { \
|
|
|
|
|
if ((head) == NULL) { \
|
|
|
|
|
(elem)->next = (elem); \
|
|
|
|
|
(elem)->prev = (elem); \
|
|
|
|
|
(head) = (elem); \
|
|
|
|
|
} else { \
|
|
|
|
|
(elem)->next = (head); \
|
|
|
|
|
(elem)->prev = (head)->prev; \
|
|
|
|
|
(head)->prev->next = (elem); \
|
|
|
|
|
(head)->prev = (elem); \
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#define LIST_REMOVE(head, elem) do { \
|
|
|
|
|
if ((elem)->next == (elem)) { \
|
|
|
|
|
ASSERT((head) == (elem)); \
|
|
|
|
|
ASSERT((elem)->prev == (elem)); \
|
|
|
|
|
(head) = NULL; \
|
|
|
|
|
} else { \
|
|
|
|
|
(elem)->prev->next = (elem)->next; \
|
|
|
|
|
(elem)->next->prev = (elem)->prev; \
|
|
|
|
|
if ((elem) == (head)) { \
|
|
|
|
|
(head)= (elem)->next; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
(elem)->next = (elem)->prev = NULL; \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#define BIT_GET(bitmap, bit) (((bitmap) >> (bit)) & (__typeof__(bitmap))1)
|
|
|
|
|
#define BIT_SET(bitmap, bit) ((bitmap) |= ((__typeof__(bitmap))1 << (bit)))
|
|
|
|
|
#define BIT_CLR(bitmap, bit) ((bitmap) &= ~((__typeof__(bitmap))1 << (bit)))
|
|
|
|
|
|
2026-05-28 16:42:51 +02:00
|
|
|
#define IS_ALIGNED_16(sz) (((uint64_t)(sz) & (uint64_t)15) == 0)
|
2026-05-30 02:13:25 +02:00
|
|
|
#define ROUND_UP_SHIFT(n, shift) ((((uint64_t)n) + ((1ull << shift) - 1)) & ~(uint64_t)((1ull << shift) - 1))
|
|
|
|
|
#define ROUND_UP_8(n) ROUND_UP_SHIFT(n, 3)
|
|
|
|
|
#define ROUND_UP_16(n) ROUND_UP_SHIFT(n, 4)
|
2026-05-28 16:42:51 +02:00
|
|
|
|
|
|
|
|
// TODO gcc says popcount cannot be found. Use manual version for now.
|
|
|
|
|
#ifdef POPCOUNT_USE_BUILTIN
|
|
|
|
|
#define IS_POWER_OF_2(n) (__builtin_popcountl(n) == 1)
|
|
|
|
|
#else
|
|
|
|
|
#define IS_POWER_OF_2(n) ((n ^ (n - 1)) > (n - 1))
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Highest bit set (0-indexed).
|
|
|
|
|
// - 4 (100) has highest bit 2.
|
|
|
|
|
// - 10 (1010) has highest bit 3.
|
|
|
|
|
// The following holds: (1 << HIGHEST_BIT_SET(sz)) <= sz
|
|
|
|
|
// Don't use for `sz == 0`.
|
|
|
|
|
#define HIGHEST_BIT_SET(sz) (63 - __builtin_clzl((uint64_t)sz))
|
|
|
|
|
|
2026-05-30 02:13:25 +02:00
|
|
|
// Don't use for `n == 0`.
|
2026-05-28 16:42:51 +02:00
|
|
|
#define LOG2(n) HIGHEST_BIT_SET(n)
|
|
|
|
|
|
2026-05-30 02:13:25 +02:00
|
|
|
// newtype so you don't accidentally access the value; use following macros to read/write
|
|
|
|
|
// TODO these are aligned, we have no way to specify unaligned ints currently
|
|
|
|
|
typedef struct le16 {
|
|
|
|
|
uint16_t value;
|
|
|
|
|
} le16;
|
|
|
|
|
typedef struct le32 {
|
|
|
|
|
uint32_t value;
|
|
|
|
|
} le32;
|
|
|
|
|
typedef struct le64 {
|
|
|
|
|
uint64_t value;
|
|
|
|
|
} le64;
|
|
|
|
|
|
|
|
|
|
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
|
|
|
|
#define CPU_TO_LE16(n) ((struct le16) { .value = n })
|
|
|
|
|
#define CPU_TO_LE32(n) ((struct le32) { .value = n })
|
|
|
|
|
#define CPU_TO_LE64(n) ((struct le64) { .value = n })
|
|
|
|
|
#define LE16_TO_CPU(n) (n).value
|
|
|
|
|
#define LE32_TO_CPU(n) (n).value
|
|
|
|
|
#define LE64_TO_CPU(n) (n).value
|
|
|
|
|
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN)
|
|
|
|
|
#define CPU_TO_LE16(n) ((struct le16) { .value = __builtin_bswap16(n) })
|
|
|
|
|
#define CPU_TO_LE32(n) ((struct le32) { .value = __builtin_bswap32(n) })
|
|
|
|
|
#define CPU_TO_LE64(n) ((struct le64) { .value = __builtin_bswap64(n) })
|
|
|
|
|
#define LE16_TO_CPU(n) __builtin_bswap16((n).value)
|
|
|
|
|
#define LE32_TO_CPU(n) __builtin_bswap32((n).value)
|
|
|
|
|
#define LE64_TO_CPU(n) __builtin_bswap64((n).value)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
2026-05-28 14:25:01 +02:00
|
|
|
#endif
|