#ifndef INCLUDED_MEMORY_H #define INCLUDED_MEMORY_H #include #include #include #include #include #include // Geneal macros #ifndef __has_attribute # define __has_attribute(attr) 0 #endif #if __has_attribute(always_inline) && defined(_NDEBUG) # define ALWAYS_INLINE inline __attribute__((always_inline)) #else # define ALWAYS_INLINE inline #endif #if __has_attribute(format) # define FORMAT(n, m) __attribute__((format(printf, n, m))) #else # define FORMAT(n, m) #endif // Byte order stuff typedef enum { ENDIAN_LITTLE, ENDIAN_BIG, } Endianness; static ALWAYS_INLINE Endianness ENDIANNESS(void) { uint16_t x = 1; return *(char *) &x == 1 ? ENDIAN_LITTLE : ENDIAN_BIG; } static ALWAYS_INLINE bool LITTLE_ENDIAN_P(void) { return ENDIANNESS() == ENDIAN_LITTLE; } // General float stuff #if SIZE_MAX == 0xffffffff # define LISP_WORD_BITS 32 #elif SIZE_MAX == 0xffffffffffffffff # define LISP_WORD_BITS 64 #else # error "Unablem to determine system word size!" #endif // Check if we support this system's floating point implementation #if FLT_RADIX != 2 || FLT_MANT_DIG != 24 || DBL_MANT_DIG != 53 \ || FLT_MAX_EXP != 128 || DBL_MAX_EXP != 1024 # error "Floating point implementation not supported." #endif typedef float lisp_float32_t; typedef double lisp_float64_t; static ALWAYS_INLINE uint32_t FLOAT32_TO_INT_BITS(lisp_float32_t flt) { union { uint32_t int_val; lisp_float32_t flt_val; } conv = {.flt_val = flt}; return conv.int_val; } static ALWAYS_INLINE uint64_t FLOAT64_TO_INT_BITS(lisp_float64_t flt) { union { uint64_t int_val; lisp_float64_t flt_val; } conv = {.flt_val = flt}; return conv.int_val; } #define FLOAT_TO_INT_BITS(flt) \ _Generic((flt), \ lisp_float32_t: FLOAT32_TO_INT_BITS(flt), \ lisp_float64_t: FLOAT64_TO_INT_BITS(flt)) static ALWAYS_INLINE lisp_float32_t INT_TO_FLOAT32_BITS(uint32_t i) { union { uint32_t int_val; lisp_float32_t flt_val; } conv = {.int_val = i}; return conv.flt_val; } static ALWAYS_INLINE lisp_float64_t INT_TO_FLOAT64_BITS(uint64_t i) { union { uint64_t int_val; lisp_float64_t flt_val; } conv = {.int_val = i}; return conv.flt_val; } #define INT_TO_FLOAT_BITS(i) \ _Generic((i), \ uint32_t: INT_TO_FLOAT32_BITS(i), \ uint64_t: INT_TO_FLOAT64_BITS(i)) // Allocator void *lisp_realloc(void *oldptr, size_t size); void *lisp_malloc(size_t size); void *lisp_malloc0(size_t size); void *lisp_aligned_alloc(size_t alignment, size_t size); #define lisp_free free // other useful things static ALWAYS_INLINE void sub_timespecs(const struct timespec *t1, const struct timespec *t2, struct timespec *out) { out->tv_sec = t1->tv_sec - t2->tv_sec; int32_t nsec = t1->tv_nsec - t2->tv_nsec; if (nsec < 0) { --out->tv_sec; nsec += 1000000000; } out->tv_nsec = nsec; } static ALWAYS_INLINE void add_timespecs(const struct timespec *t1, const struct timespec *t2, struct timespec *out) { out->tv_sec = t1->tv_sec + t2->tv_sec; int32_t nsec = t1->tv_nsec + t2->tv_nsec; if (nsec > 1000000000) { ++out->tv_sec; nsec -= 1000000000; } out->tv_nsec = nsec; } typedef struct { // this is actually size + 1 bytes for the null byte char *buffer; size_t size; size_t nchars; } StringStream; static inline void string_stream_init(StringStream *restrict stream) { stream->buffer = lisp_malloc(1); stream->size = 0; stream->buffer[stream->size] = '\0'; stream->nchars = 0; } static inline void string_stream_free(StringStream *restrict stream) { lisp_free(stream->buffer); } static inline void string_stream_steal(StringStream *restrict stream, char **restrict out, size_t *restrict out_length) { *out = stream->buffer; *out_length = stream->nchars; } int string_stream_printf(StringStream *restrict stream, const char *restrict format, ...) FORMAT(2, 3); int string_stream_vprintf(StringStream *restrict stream, const char *restrict format, va_list args); // Get the next line in BUF starting at *START (or &buf[0] if *START is // NULL). Store the length of the line in LENGTH. BUF is BUF_LENGTH bytes // long. Return true if we found another line and false otherwise. bool strgetline(const char *restrict buf, size_t buf_length, const char **restrict start, size_t *restrict length); #endif