170 lines
4.8 KiB
C
170 lines
4.8 KiB
C
#ifndef INCLUDED_MEMORY_H
|
|
#define INCLUDED_MEMORY_H
|
|
|
|
#include <float.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
// 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
|