Refactor to use portable minimum-width integers.
The signed and unsigned fixed-width integers (int32_t, uint32_t etc.) are optional in C99 (and above). Use the non-optional minimum-width integers (int_fast32_t, uint_fast32_t and int_least32_t, uint_least32_t etc.) instead. To simulate unsigned wrap-around, use the GUF_UWRAP macros in guf_common.h cf. https://en.cppreference.com/w/c/types/integer (last-retrieved: 2025-05-18)
This commit is contained in:
parent
7ec2af0c33
commit
57f0e47efc
@ -16,13 +16,13 @@ typedef struct guf_alloc_tracker {
|
|||||||
const char *name;
|
const char *name;
|
||||||
size_t alloc_count, realloc_count, free_count;
|
size_t alloc_count, realloc_count, free_count;
|
||||||
ptrdiff_t allocated_bytes;
|
ptrdiff_t allocated_bytes;
|
||||||
uint32_t id;
|
unsigned id;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
} guf_alloc_tracker;
|
} guf_alloc_tracker;
|
||||||
|
|
||||||
#if !defined(GUF_ALLOC_TRACKER_IMPL_STATIC) && !defined(GUF_ALLOC_TRACKER_IMPL)
|
#if !defined(GUF_ALLOC_TRACKER_IMPL_STATIC) && !defined(GUF_ALLOC_TRACKER_IMPL)
|
||||||
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, uint32_t id, const char* name, FILE *log, FILE *err_log);
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, unsigned id, const char* name, FILE *log, FILE *err_log);
|
||||||
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker guf_alloc_tracker_new(uint32_t id, const char* name, FILE *log, FILE *err_log);
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker guf_alloc_tracker_new(unsigned id, const char* name, FILE *log, FILE *err_log);
|
||||||
|
|
||||||
GUF_ALLOC_TRACKER_KWRDS void guf_alloc_tracker_print(const guf_alloc_tracker *t, FILE *f);
|
GUF_ALLOC_TRACKER_KWRDS void guf_alloc_tracker_print(const guf_alloc_tracker *t, FILE *f);
|
||||||
GUF_ALLOC_TRACKER_KWRDS bool guf_alloc_tracker_found_leak(const guf_alloc_tracker *t);
|
GUF_ALLOC_TRACKER_KWRDS bool guf_alloc_tracker_found_leak(const guf_alloc_tracker *t);
|
||||||
@ -38,7 +38,7 @@ typedef struct guf_alloc_tracker {
|
|||||||
#define GUF_MATH_CKDINT_IMPL_STATIC
|
#define GUF_MATH_CKDINT_IMPL_STATIC
|
||||||
#include "guf_math_ckdint.h"
|
#include "guf_math_ckdint.h"
|
||||||
|
|
||||||
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, uint32_t id, const char* name, FILE *log, FILE *err_log)
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, unsigned id, const char* name, FILE *log, FILE *err_log)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(t);
|
GUF_ASSERT_RELEASE(t);
|
||||||
t->log = log;
|
t->log = log;
|
||||||
@ -51,7 +51,7 @@ GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_trac
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker guf_alloc_tracker_new(uint32_t id, const char* name, FILE *log, FILE *err_log)
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker guf_alloc_tracker_new(unsigned id, const char* name, FILE *log, FILE *err_log)
|
||||||
{
|
{
|
||||||
guf_alloc_tracker t;
|
guf_alloc_tracker t;
|
||||||
guf_alloc_tracker_init(&t, id, name, log, err_log);
|
guf_alloc_tracker_init(&t, id, name, log, err_log);
|
||||||
@ -78,7 +78,7 @@ GUF_ALLOC_TRACKER_KWRDS void guf_alloc_tracker_print(const guf_alloc_tracker *t,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"guf_alloc_tracker (name '%s' id = %" PRIu32 "):\n"
|
"guf_alloc_tracker (name '%s' id = %u):\n"
|
||||||
"allocated_bytes: %td\n"
|
"allocated_bytes: %td\n"
|
||||||
"alloc_count: %zu\n"
|
"alloc_count: %zu\n"
|
||||||
"realloc_count: %zu\n"
|
"realloc_count: %zu\n"
|
||||||
@ -96,25 +96,25 @@ GUF_ALLOC_TRACKER_KWRDS bool guf_track_alloc(guf_alloc_tracker *t, ptrdiff_t siz
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
if (guf_saturating_add_size_t(t->alloc_count, 1, &t->alloc_count) != GUF_MATH_CKD_SUCCESS && t->err_log) {
|
if (guf_saturating_add_size_t(t->alloc_count, 1, &t->alloc_count) != GUF_MATH_CKD_SUCCESS && t->err_log) {
|
||||||
fprintf(t->err_log, "WARNING in guf_track_alloc (name '%s' id %" PRIu32 "): alloc_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "WARNING in guf_track_alloc (name '%s' id %u): alloc_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes) != GUF_MATH_CKD_SUCCESS) {
|
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes) != GUF_MATH_CKD_SUCCESS) {
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_alloc (name '%s' id %" PRIu32 "): allocated_byte overflow\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_alloc (name '%s' id %u): allocated_byte overflow\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->allocated_bytes < 0) {
|
if (t->allocated_bytes < 0) {
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_alloc (name '%s' id %" PRIu32 "): allocated_bytes < 0\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_alloc (name '%s' id %u): allocated_bytes < 0\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->log) {
|
if (t->log) {
|
||||||
fprintf(t->log, "guf_alloc_tracker (name '%s' id %" PRIu32 "): alloc (%td bytes) %s\n", t->name ? t->name : "unnamed", t->id, size, success ? "SUCCESS" : "FAILURE");
|
fprintf(t->log, "guf_alloc_tracker (name '%s' id %u): alloc (%td bytes) %s\n", t->name ? t->name : "unnamed", t->id, size, success ? "SUCCESS" : "FAILURE");
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -127,40 +127,40 @@ GUF_ALLOC_TRACKER_KWRDS bool guf_track_realloc(guf_alloc_tracker *t, ptrdiff_t o
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
if (guf_saturating_add_size_t(t->realloc_count, 1, &t->realloc_count) && t->err_log) {
|
if (guf_saturating_add_size_t(t->realloc_count, 1, &t->realloc_count) && t->err_log) {
|
||||||
fprintf(t->err_log, "WARNING in guf_track_realloc (name '%s' id %" PRIu32 "): realloc_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "WARNING in guf_track_realloc (name '%s' id %u): realloc_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_size < 0 || new_size < 0) {
|
if (old_size < 0 || new_size < 0) {
|
||||||
success = false;
|
success = false;
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %" PRIu32 "): old_size < 0 or new_size < 0\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): old_size < 0 or new_size < 0\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, old_size, &t->allocated_bytes)) {
|
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, old_size, &t->allocated_bytes)) {
|
||||||
success = false;
|
success = false;
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %" PRIu32 "): allocated_bytes - old_size under/overflows\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes - old_size under/overflows\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (t->allocated_bytes < 0) {
|
if (t->allocated_bytes < 0) {
|
||||||
success = false;
|
success = false;
|
||||||
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %" PRIu32 "): allocated_bytes < 0 after subtracting old_size\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes < 0 after subtracting old_size\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, new_size, &t->allocated_bytes)) {
|
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, new_size, &t->allocated_bytes)) {
|
||||||
success = false;
|
success = false;
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %" PRIu32 "): allocated_bytes overflow \n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes overflow \n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (t->allocated_bytes < 0) {
|
if (t->allocated_bytes < 0) {
|
||||||
success = false;
|
success = false;
|
||||||
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %" PRIu32 "): allocated_bytes < 0 after adding new_size\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes < 0 after adding new_size\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->log) {
|
if (t->log) {
|
||||||
fprintf(t->log, "guf_alloc_tracker (name '%s' id %" PRIu32 "): realloc (from %td to %td bytes) %s\n", t->name ? t->name : "unnamed", t->id, old_size, new_size, (success ? "SUCCESS" : "FAILURE"));
|
fprintf(t->log, "guf_alloc_tracker (name '%s' id %u): realloc (from %td to %td bytes) %s\n", t->name ? t->name : "unnamed", t->id, old_size, new_size, (success ? "SUCCESS" : "FAILURE"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -173,31 +173,31 @@ GUF_ALLOC_TRACKER_KWRDS bool guf_track_free(guf_alloc_tracker *t, ptrdiff_t size
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
if (guf_saturating_add_size_t(t->free_count, 1, &t->free_count) && t->err_log) {
|
if (guf_saturating_add_size_t(t->free_count, 1, &t->free_count) && t->err_log) {
|
||||||
fprintf(t->err_log, "WARNING in guf_track_free (name '%s' id %" PRIu32 "): free_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "WARNING in guf_track_free (name '%s' id %u): free_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
success = false;
|
success = false;
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %" PRIu32 "): size < 0\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %u): size < 0\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->allocated_bytes < size) {
|
if (t->allocated_bytes < size) {
|
||||||
success = false;
|
success = false;
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %" PRIu32 "): freed more bytes than allocated\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %u): freed more bytes than allocated\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes)) {
|
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes)) {
|
||||||
success = false;
|
success = false;
|
||||||
if (t->err_log) {
|
if (t->err_log) {
|
||||||
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %" PRIu32 "): allocated_bytes - size under/overflows\n", t->name ? t->name : "unnamed", t->id);
|
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %u): allocated_bytes - size under/overflows\n", t->name ? t->name : "unnamed", t->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->log) {
|
if (t->log) {
|
||||||
fprintf(t->log, "guf_alloc_tracker (name '%s' id %" PRIu32 "): free (%td bytes) %s\n", t->name ? t->name : "unnamed", t->id, size, (success ? "SUCCESS" : "FAILURE"));
|
fprintf(t->log, "guf_alloc_tracker (name '%s' id %u): free (%td bytes) %s\n", t->name ? t->name : "unnamed", t->id, size, (success ? "SUCCESS" : "FAILURE"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
|||||||
@ -10,22 +10,39 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef GUF_PLATFORM_BIG_ENDIAN
|
||||||
|
#define GUF_PLATFORM_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
#define GUF_UINT8_MAX 0xffu
|
#define GUF_UINT8_MAX 0xffu
|
||||||
#define GUF_UINT16_MAX 0xffffu
|
#define GUF_UINT16_MAX 0xffffu
|
||||||
#define GUF_UINT32_MAX 0xfffffffful
|
#define GUF_UINT32_MAX 0xfffffffful
|
||||||
#define GUF_UINT64_MAX 0xffffffffffffffffull
|
#define GUF_UINT64_MAX 0xffffffffffffffffull
|
||||||
|
|
||||||
#ifndef GUF_PLATFORM_BIG_ENDIAN
|
#define GUF_UWRAP_8(UINT) ( (UINT) & GUF_UINT8_MAX )
|
||||||
#define GUF_PLATFORM_LITTLE_ENDIAN
|
#define GUF_UWRAP_16(UINT) ( (UINT) & GUF_UINT16_MAX )
|
||||||
#endif
|
#define GUF_UWRAP_32(UINT) ( (UINT) & GUF_UINT32_MAX )
|
||||||
|
#define GUF_UWRAP_64(UINT) ( (UINT) & GUF_UINT64_MAX )
|
||||||
|
|
||||||
#if SIZE_MAX == UINT64_MAX
|
#define GUF_INT8_MAX 127
|
||||||
|
#define GUF_INT8_MIN -128
|
||||||
|
|
||||||
|
#define GUF_INT16_MAX 32767
|
||||||
|
#define GUF_INT16_MIN (-GUF_INT16_MAX - 1)
|
||||||
|
|
||||||
|
#define GUF_INT32_MAX 2147483647L
|
||||||
|
#define GUF_INT32_MIN (-GUF_INT32_MAX - 1)
|
||||||
|
|
||||||
|
#define GUF_INT64_MAX 9223372036854775807LL
|
||||||
|
#define GUF_INT64_MIN (-GUF_INT64_MAX - 1)
|
||||||
|
|
||||||
|
#if SIZE_MAX == GUF_UINT64_MAX
|
||||||
#define GUF_PLATFORM_BITS 64
|
#define GUF_PLATFORM_BITS 64
|
||||||
#elif SIZE_MAX == UINT32_MAX
|
#elif SIZE_MAX == GUF_UINT32_MAX
|
||||||
#define GUF_PLATFORM_BITS 32
|
#define GUF_PLATFORM_BITS 32
|
||||||
#elif SIZE_MAX == UINT16_MAX
|
#elif SIZE_MAX == GUF_UINT16_MAX
|
||||||
#define GUF_PLATFORM_BITS 16
|
#define GUF_PLATFORM_BITS 16
|
||||||
#elif SIZE_MAX == UINT8_MAX
|
#elif SIZE_MAX == GUF_UINT8_MAX
|
||||||
#define GUF_PLATFORM_BITS 8
|
#define GUF_PLATFORM_BITS 8
|
||||||
#else
|
#else
|
||||||
#define GUF_PLATFORM_BITS 64
|
#define GUF_PLATFORM_BITS 64
|
||||||
|
|||||||
@ -34,18 +34,18 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GUF_DICT_32_BIT_HASH)
|
#if defined(GUF_DICT_32_BIT_HASH)
|
||||||
#define GUF_DICT_HASH_T uint32_t
|
#define GUF_DICT_HASH_T uint_fast32_t
|
||||||
#define GUF_DICT_HASH_T_MAX UINT32_MAX
|
#define GUF_DICT_HASH_T_MAX GUF_UINT32_MAX
|
||||||
#elif defined(GUF_DICT_64_BIT_HASH)
|
#elif defined(GUF_DICT_64_BIT_HASH)
|
||||||
#define GUF_DICT_HASH_T uint64_t
|
#define GUF_DICT_HASH_T uint_fast64_t
|
||||||
#define GUF_DICT_HASH_T_MAX UINT64_MAX
|
#define GUF_DICT_HASH_T_MAX GUF_UINT64_MAX
|
||||||
#else
|
#else
|
||||||
#define GUF_DICT_HASH_T guf_hash_size_t
|
#define GUF_DICT_HASH_T guf_hash_size_t
|
||||||
#define GUF_DICT_HASH_T_MAX GUF_HASH_MAX
|
#define GUF_DICT_HASH_T_MAX GUF_HASH_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (GUF_DICT_64_BIT_IDX)
|
#if defined (GUF_DICT_64_BIT_IDX)
|
||||||
#define GUF_DICT_KV_META_T uint64_t
|
#define GUF_DICT_KV_META_T uint_least64_t
|
||||||
/*
|
/*
|
||||||
Store a 16-bit hash-fragment in the upper 16-bits of kv_meta
|
Store a 16-bit hash-fragment in the upper 16-bits of kv_meta
|
||||||
-> (2^48 - 1 is IDX_NULL, 2^48 - 2 is IDX_TOMBSTONE, 2^48 - 3 is the largest actual idx,
|
-> (2^48 - 1 is IDX_NULL, 2^48 - 2 is IDX_TOMBSTONE, 2^48 - 3 is the largest actual idx,
|
||||||
@ -54,15 +54,15 @@
|
|||||||
#define GUF_DICT_KV_META_HASHFRAG_MASK UINT64_C(0xffff000000000000)
|
#define GUF_DICT_KV_META_HASHFRAG_MASK UINT64_C(0xffff000000000000)
|
||||||
#define GUF_DICT_KV_META_IDX_MASK (~UINT64_C(0xffff000000000000))
|
#define GUF_DICT_KV_META_IDX_MASK (~UINT64_C(0xffff000000000000))
|
||||||
|
|
||||||
#if GUF_DICT_HASH_T_MAX == UINT64_MAX
|
#if GUF_DICT_HASH_T_MAX == GUF_UINT64_MAX
|
||||||
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( (HASH) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( (HASH) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
||||||
#elif GUF_DICT_HASH_T_MAX == UINT32_MAX
|
#elif GUF_DICT_HASH_T_MAX == GUF_UINT32_MAX
|
||||||
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( (((uint64_t)(HASH)) << 32) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( (((uint_least64_t)(HASH)) << 32u) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
||||||
#else
|
#else
|
||||||
#error "guf_dict: invalid hash size (should not happen)"
|
#error "guf_dict: invalid hash size (should not happen)"
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define GUF_DICT_KV_META_T uint32_t
|
#define GUF_DICT_KV_META_T uint_least32_t
|
||||||
/*
|
/*
|
||||||
Store a 7-bit hash-fragment in the upper 7-bits of kv_meta
|
Store a 7-bit hash-fragment in the upper 7-bits of kv_meta
|
||||||
-> (2^25 - 1 is IDX_NULL, 2^25 - 2 is IDX_TOMBSTONE, 2^25 - 3 is the largest actual idx,
|
-> (2^25 - 1 is IDX_NULL, 2^25 - 2 is IDX_TOMBSTONE, 2^25 - 3 is the largest actual idx,
|
||||||
@ -71,9 +71,9 @@
|
|||||||
#define GUF_DICT_KV_META_HASHFRAG_MASK UINT32_C(0xfe000000)
|
#define GUF_DICT_KV_META_HASHFRAG_MASK UINT32_C(0xfe000000)
|
||||||
#define GUF_DICT_KV_META_IDX_MASK (~UINT32_C(0xfe000000))
|
#define GUF_DICT_KV_META_IDX_MASK (~UINT32_C(0xfe000000))
|
||||||
|
|
||||||
#if GUF_DICT_HASH_T_MAX == UINT64_MAX
|
#if GUF_DICT_HASH_T_MAX == GUF_UINT64_MAX
|
||||||
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( ((uint32_t)((HASH) >> 32)) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( ((uint_least32_t)((HASH) >> 32u)) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
||||||
#elif GUF_DICT_HASH_T_MAX == UINT32_MAX
|
#elif GUF_DICT_HASH_T_MAX == GUF_UINT32_MAX
|
||||||
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( (HASH) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
#define GUF_DICT_HASH_T_GET_HASHFRAG(HASH) ( (HASH) & GUF_DICT_KV_META_HASHFRAG_MASK )
|
||||||
#else
|
#else
|
||||||
#error "guf_dict: invalid hash size (should not happen)"
|
#error "guf_dict: invalid hash size (should not happen)"
|
||||||
@ -447,10 +447,11 @@ static inline size_t GUF_CAT(GUF_DICT_NAME, _probe_offset_)(size_t probe_len)
|
|||||||
return probe_len; // 1, 2, 3, 4, 5, ...
|
return probe_len; // 1, 2, 3, 4, 5, ...
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
|
Quadratic probing:
|
||||||
Guaranteed to visit each index once for capacities which are powers of two.
|
Guaranteed to visit each index once for capacities which are powers of two.
|
||||||
cf. https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/ (last-retrieved 2024-07-29)
|
cf. https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/ (last-retrieved 2024-07-29)
|
||||||
*/
|
*/
|
||||||
return probe_len * (probe_len + 1) / 2; // 1, 3, 6, 10, 15, 21 ... (starting from probe_len == 1)
|
return probe_len * (probe_len + 1u) / 2u; // 1, 3, 6, 10, 15, 21 ... (starting from probe_len == 1)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,29 +19,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define GUF_HASH32_INIT UINT32_C(2166136261)
|
#define GUF_HASH32_INIT UINT32_C(2166136261)
|
||||||
#ifdef UINT64_MAX
|
|
||||||
#define GUF_HASH64_INIT UINT64_C(14695981039346656037)
|
#define GUF_HASH64_INIT UINT64_C(14695981039346656037)
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_HASH_KWRDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash); // FNV-1a (32 bit)
|
GUF_HASH_KWRDS uint_fast32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint_fast32_t hash); // FNV-1a (32 bit)
|
||||||
#ifdef UINT64_MAX
|
GUF_HASH_KWRDS uint_fast64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint_fast64_t hash); // FNV-1a (64 bit)
|
||||||
GUF_HASH_KWRDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash); // FNV-1a (64 bit)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GUF_HASH_32_BIT
|
#ifdef GUF_HASH_32_BIT
|
||||||
typedef uint32_t guf_hash_size_t;
|
typedef uint_fast32_t guf_hash_size_t;
|
||||||
#define GUF_HASH_INIT GUF_HASH32_INIT
|
#define GUF_HASH_INIT GUF_HASH32_INIT
|
||||||
#define GUF_HASH_MAX UINT32_MAX
|
#define GUF_HASH_MAX GUF_UINT32_MAX
|
||||||
static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, guf_hash_size_t hash) {
|
static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, guf_hash_size_t hash) {
|
||||||
return guf_hash32(data, num_bytes, hash);
|
return guf_hash32(data, num_bytes, hash);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifndef UINT64_MAX
|
typedef uint_fast64_t guf_hash_size_t;
|
||||||
#error "guf_hash.h: Platform does not support uint64_t (define GUF_HASH_32_BIT to fix)"
|
|
||||||
#endif
|
|
||||||
typedef uint64_t guf_hash_size_t;
|
|
||||||
#define GUF_HASH_INIT GUF_HASH64_INIT
|
#define GUF_HASH_INIT GUF_HASH64_INIT
|
||||||
#define GUF_HASH_MAX UINT64_MAX
|
#define GUF_HASH_MAX GUF_UINT64_MAX
|
||||||
static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, guf_hash_size_t hash) {
|
static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, guf_hash_size_t hash) {
|
||||||
return guf_hash64(data, num_bytes, hash);
|
return guf_hash64(data, num_bytes, hash);
|
||||||
}
|
}
|
||||||
@ -53,36 +46,37 @@ GUF_HASH_KWRDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32
|
|||||||
|
|
||||||
#include "guf_assert.h"
|
#include "guf_assert.h"
|
||||||
|
|
||||||
GUF_HASH_KWRDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash)
|
GUF_HASH_KWRDS uint_fast32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint_fast32_t hash)
|
||||||
{
|
{
|
||||||
|
hash = GUF_UWRAP_32(hash);
|
||||||
GUF_ASSERT_RELEASE(data);
|
GUF_ASSERT_RELEASE(data);
|
||||||
GUF_ASSERT_RELEASE(num_bytes >= 0);
|
GUF_ASSERT_RELEASE(num_bytes >= 0);
|
||||||
const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think...
|
const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think...
|
||||||
const uint32_t FNV_32_PRIME = UINT32_C(16777619);
|
const uint_fast32_t FNV_32_PRIME = UINT32_C(16777619);
|
||||||
for (ptrdiff_t i = 0; i < num_bytes; ++i) {
|
for (ptrdiff_t i = 0; i < num_bytes; ++i) {
|
||||||
hash ^= 1u * data_bytes[i];
|
hash = GUF_UWRAP_32(1u * hash ^ data_bytes[i]);
|
||||||
hash *= 1u * FNV_32_PRIME;
|
hash = GUF_UWRAP_32(1u * hash * FNV_32_PRIME);
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
GUF_HASH_KWRDS uint_fast64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint_fast64_t hash)
|
||||||
GUF_HASH_KWRDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash)
|
|
||||||
{
|
{
|
||||||
|
hash = GUF_UWRAP_64(hash);
|
||||||
GUF_ASSERT_RELEASE(data);
|
GUF_ASSERT_RELEASE(data);
|
||||||
GUF_ASSERT_RELEASE(num_bytes >= 0);
|
GUF_ASSERT_RELEASE(num_bytes >= 0);
|
||||||
const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think...
|
const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think...
|
||||||
const uint64_t FNV_64_PRIME = UINT64_C(1099511628211);
|
const uint_fast64_t FNV_64_PRIME = UINT64_C(1099511628211);
|
||||||
for (ptrdiff_t i = 0; i < num_bytes; ++i) {
|
for (ptrdiff_t i = 0; i < num_bytes; ++i) {
|
||||||
hash ^= 1u * data_bytes[i];
|
hash = GUF_UWRAP_64(1u * hash ^ data_bytes[i]);
|
||||||
hash *= 1u * FNV_64_PRIME;
|
hash = GUF_UWRAP_64(1u * hash * FNV_64_PRIME);
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef GUF_HASH_IMPL
|
#undef GUF_HASH_IMPL
|
||||||
#undef GUF_HASH_IMPL_STATIC
|
#undef GUF_HASH_IMPL_STATIC
|
||||||
|
|
||||||
#endif /* endif GUF_IMPL/GUF_IMPL_STATIC */
|
#endif /* endif GUF_IMPL/GUF_IMPL_STATIC */
|
||||||
|
|
||||||
#undef GUF_HASH_KWRDS
|
#undef GUF_HASH_KWRDS
|
||||||
|
|||||||
242
src/guf_math.h
242
src/guf_math.h
@ -15,10 +15,6 @@
|
|||||||
#define GUF_MAX_F32_LT_ONE (1.f - FLT_EPSILON/FLT_RADIX)
|
#define GUF_MAX_F32_LT_ONE (1.f - FLT_EPSILON/FLT_RADIX)
|
||||||
#define GUF_MAX_F64_LT_ONE (1.0 - DBL_EPSILON/FLT_RADIX)
|
#define GUF_MAX_F64_LT_ONE (1.0 - DBL_EPSILON/FLT_RADIX)
|
||||||
|
|
||||||
// Rotate left.
|
|
||||||
static inline uint64_t guf_rotl_u64(uint64_t x, int k) {return (1u*x << k) | (1u*x >> (64 - k));}
|
|
||||||
static inline uint32_t guf_rotl_u32(uint32_t x, int k) {return (1u*x << k) | (1u*x >> (32 - k));}
|
|
||||||
|
|
||||||
// Typesafe unsigned integer wrapping functions (generated with libguf/tools/intwrap-gen.py)
|
// Typesafe unsigned integer wrapping functions (generated with libguf/tools/intwrap-gen.py)
|
||||||
static inline uint_least8_t guf_wrap8_uint_least8_t(uint_least8_t a) { return a & GUF_UINT8_MAX; }
|
static inline uint_least8_t guf_wrap8_uint_least8_t(uint_least8_t a) { return a & GUF_UINT8_MAX; }
|
||||||
static inline uint_fast8_t guf_wrap8_uint_fast8_t(uint_fast8_t a) { return a & GUF_UINT8_MAX; }
|
static inline uint_fast8_t guf_wrap8_uint_fast8_t(uint_fast8_t a) { return a & GUF_UINT8_MAX; }
|
||||||
@ -37,13 +33,50 @@ static inline unsigned short guf_wrap16_ushort(unsigned short a) { r
|
|||||||
static inline unsigned long guf_wrap32_ulong(unsigned long a) { return a & GUF_UINT32_MAX; } // unsigned long: >= 32 bits
|
static inline unsigned long guf_wrap32_ulong(unsigned long a) { return a & GUF_UINT32_MAX; } // unsigned long: >= 32 bits
|
||||||
static inline unsigned long long guf_wrap64_ulong_long(unsigned long long a) { return a & GUF_UINT64_MAX; } // unsigned long long: >= 64 bits
|
static inline unsigned long long guf_wrap64_ulong_long(unsigned long long a) { return a & GUF_UINT64_MAX; } // unsigned long long: >= 64 bits
|
||||||
|
|
||||||
#define GUF_UWRAP_8(UINT) ( (UINT) & GUF_UINT8_MAX )
|
// Rotate left.
|
||||||
#define GUF_UWRAP_16(UINT) ( (UINT) & GUF_UINT16_MAX )
|
#ifdef UINT32_MAX
|
||||||
#define GUF_UWRAP_32(UINT) ( (UINT) & GUF_UINT32_MAX )
|
static inline uint32_t guf_rotl_u32(uint32_t x, int k)
|
||||||
#define GUF_UWRAP_64(UINT) ( (UINT) & GUF_UINT64_MAX )
|
{
|
||||||
|
GUF_ASSERT(k > 0);
|
||||||
|
return (1u*x << k) | (1u*x >> (32 - k));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef UINT64_MAX
|
||||||
|
static inline uint64_t guf_rotl_u64(uint64_t x, int k)
|
||||||
|
{
|
||||||
|
GUF_ASSERT(k > 0);
|
||||||
|
return (1u*x << k) | (1u*x >> (64 - k));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline uint_fast32_t guf_rotl32_uint_fast32_t(uint_fast32_t x, int k)
|
||||||
|
{
|
||||||
|
GUF_ASSERT(k > 0);
|
||||||
|
x = guf_wrap32_uint_fast32_t(x);
|
||||||
|
return guf_wrap32_uint_fast32_t( (1u*x << k) | (1u*x >> (32 - k)) );
|
||||||
|
}
|
||||||
|
static inline uint_fast64_t guf_rotl64_uint_fast64_t(uint_fast64_t x, int k)
|
||||||
|
{
|
||||||
|
GUF_ASSERT(k > 0);
|
||||||
|
x = guf_wrap64_uint_fast64_t(x);
|
||||||
|
return guf_wrap64_uint_fast64_t( (1u*x << k) | (1u*x >> (64 - k)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long guf_rotl32_ulong(unsigned long x, int k)
|
||||||
|
{
|
||||||
|
GUF_ASSERT(k > 0);
|
||||||
|
x = guf_wrap32_ulong(x);
|
||||||
|
return guf_wrap32_ulong( (x << k) | (x >> (32 - k)) );
|
||||||
|
}
|
||||||
|
static inline unsigned long long guf_rotl64_ulong_long(unsigned long long x, int k)
|
||||||
|
{
|
||||||
|
GUF_ASSERT(k > 0);
|
||||||
|
x = guf_wrap64_ulong_long(x);
|
||||||
|
return guf_wrap64_ulong_long( (x << k) | (x >> (64 - k)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Signed min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)
|
// Signed min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)
|
||||||
|
|
||||||
static inline char guf_min_char(char a, char b) { return a < b ? a : b; }
|
static inline char guf_min_char(char a, char b) { return a < b ? a : b; }
|
||||||
static inline char guf_max_char(char a, char b) { return a > b ? a : b; }
|
static inline char guf_max_char(char a, char b) { return a > b ? a : b; }
|
||||||
static inline char guf_clamp_char(char x, char min, char max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline char guf_clamp_char(char x, char min, char max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
@ -60,26 +93,26 @@ static inline long long guf_min_long_long(long long a, long long b) { return a <
|
|||||||
static inline long long guf_max_long_long(long long a, long long b) { return a > b ? a : b; }
|
static inline long long guf_max_long_long(long long a, long long b) { return a > b ? a : b; }
|
||||||
static inline long long guf_clamp_long_long(long long x, long long min, long long max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline long long guf_clamp_long_long(long long x, long long min, long long max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
static inline int8_t guf_min_i8(int8_t a, int8_t b) { return a < b ? a : b; }
|
|
||||||
static inline int8_t guf_max_i8(int8_t a, int8_t b) { return a > b ? a : b; }
|
|
||||||
static inline int8_t guf_clamp_i8(int8_t x, int8_t min, int8_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline int16_t guf_min_i16(int16_t a, int16_t b) { return a < b ? a : b; }
|
|
||||||
static inline int16_t guf_max_i16(int16_t a, int16_t b) { return a > b ? a : b; }
|
|
||||||
static inline int16_t guf_clamp_i16(int16_t x, int16_t min, int16_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline int32_t guf_min_i32(int32_t a, int32_t b) { return a < b ? a : b; }
|
|
||||||
static inline int32_t guf_max_i32(int32_t a, int32_t b) { return a > b ? a : b; }
|
|
||||||
static inline int32_t guf_clamp_i32(int32_t x, int32_t min, int32_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline int64_t guf_min_i64(int64_t a, int64_t b) { return a < b ? a : b; }
|
|
||||||
static inline int64_t guf_max_i64(int64_t a, int64_t b) { return a > b ? a : b; }
|
|
||||||
static inline int64_t guf_clamp_i64(int64_t x, int64_t min, int64_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline ptrdiff_t guf_min_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) { return a < b ? a : b; }
|
static inline ptrdiff_t guf_min_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) { return a < b ? a : b; }
|
||||||
static inline ptrdiff_t guf_max_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) { return a > b ? a : b; }
|
static inline ptrdiff_t guf_max_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) { return a > b ? a : b; }
|
||||||
static inline ptrdiff_t guf_clamp_ptrdiff_t(ptrdiff_t x, ptrdiff_t min, ptrdiff_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline ptrdiff_t guf_clamp_ptrdiff_t(ptrdiff_t x, ptrdiff_t min, ptrdiff_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline int_fast8_t guf_min_i8_fast(int_fast8_t a, int_fast8_t b) { return a < b ? a : b; }
|
||||||
|
static inline int_fast8_t guf_max_i8_fast(int_fast8_t a, int_fast8_t b) { return a > b ? a : b; }
|
||||||
|
static inline int_fast8_t guf_clamp_i8_fast(int_fast8_t x, int_fast8_t min, int_fast8_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline int_fast16_t guf_min_i16_fast(int_fast16_t a, int_fast16_t b) { return a < b ? a : b; }
|
||||||
|
static inline int_fast16_t guf_max_i16_fast(int_fast16_t a, int_fast16_t b) { return a > b ? a : b; }
|
||||||
|
static inline int_fast16_t guf_clamp_i16_fast(int_fast16_t x, int_fast16_t min, int_fast16_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline int_fast32_t guf_min_i32_fast(int_fast32_t a, int_fast32_t b) { return a < b ? a : b; }
|
||||||
|
static inline int_fast32_t guf_max_i32_fast(int_fast32_t a, int_fast32_t b) { return a > b ? a : b; }
|
||||||
|
static inline int_fast32_t guf_clamp_i32_fast(int_fast32_t x, int_fast32_t min, int_fast32_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline int_fast64_t guf_min_i64_fast(int_fast64_t a, int_fast64_t b) { return a < b ? a : b; }
|
||||||
|
static inline int_fast64_t guf_max_i64_fast(int_fast64_t a, int_fast64_t b) { return a > b ? a : b; }
|
||||||
|
static inline int_fast64_t guf_clamp_i64_fast(int_fast64_t x, int_fast64_t min, int_fast64_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
static inline float guf_min_f32(float a, float b) { return a < b ? a : b; }
|
static inline float guf_min_f32(float a, float b) { return a < b ? a : b; }
|
||||||
static inline float guf_max_f32(float a, float b) { return a > b ? a : b; }
|
static inline float guf_max_f32(float a, float b) { return a > b ? a : b; }
|
||||||
static inline float guf_clamp_f32(float x, float min, float max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline float guf_clamp_f32(float x, float min, float max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
@ -88,8 +121,31 @@ static inline double guf_min_f64(double a, double b) { return a < b ? a : b; }
|
|||||||
static inline double guf_max_f64(double a, double b) { return a > b ? a : b; }
|
static inline double guf_max_f64(double a, double b) { return a > b ? a : b; }
|
||||||
static inline double guf_clamp_f64(double x, double min, double max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline double guf_clamp_f64(double x, double min, double max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
// Unsigned min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)
|
#ifdef INT8_MAX
|
||||||
|
static inline int8_t guf_min_i8(int8_t a, int8_t b) { return a < b ? a : b; }
|
||||||
|
static inline int8_t guf_max_i8(int8_t a, int8_t b) { return a > b ? a : b; }
|
||||||
|
static inline int8_t guf_clamp_i8(int8_t x, int8_t min, int8_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INT16_MAX
|
||||||
|
static inline int16_t guf_min_i16(int16_t a, int16_t b) { return a < b ? a : b; }
|
||||||
|
static inline int16_t guf_max_i16(int16_t a, int16_t b) { return a > b ? a : b; }
|
||||||
|
static inline int16_t guf_clamp_i16(int16_t x, int16_t min, int16_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INT32_MAX
|
||||||
|
static inline int32_t guf_min_i32(int32_t a, int32_t b) { return a < b ? a : b; }
|
||||||
|
static inline int32_t guf_max_i32(int32_t a, int32_t b) { return a > b ? a : b; }
|
||||||
|
static inline int32_t guf_clamp_i32(int32_t x, int32_t min, int32_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INT64_MAX
|
||||||
|
static inline int64_t guf_min_i64(int64_t a, int64_t b) { return a < b ? a : b; }
|
||||||
|
static inline int64_t guf_max_i64(int64_t a, int64_t b) { return a > b ? a : b; }
|
||||||
|
static inline int64_t guf_clamp_i64(int64_t x, int64_t min, int64_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Unsigned min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)
|
||||||
static inline unsigned char guf_min_uchar(unsigned char a, unsigned char b) { return a < b ? a : b; }
|
static inline unsigned char guf_min_uchar(unsigned char a, unsigned char b) { return a < b ? a : b; }
|
||||||
static inline unsigned char guf_max_uchar(unsigned char a, unsigned char b) { return a > b ? a : b; }
|
static inline unsigned char guf_max_uchar(unsigned char a, unsigned char b) { return a > b ? a : b; }
|
||||||
static inline unsigned char guf_clamp_uchar(unsigned char x, unsigned char min, unsigned char max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline unsigned char guf_clamp_uchar(unsigned char x, unsigned char min, unsigned char max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
@ -106,52 +162,104 @@ static inline unsigned long long guf_min_ulong_long(unsigned long long a, unsign
|
|||||||
static inline unsigned long long guf_max_ulong_long(unsigned long long a, unsigned long long b) { return a > b ? a : b; }
|
static inline unsigned long long guf_max_ulong_long(unsigned long long a, unsigned long long b) { return a > b ? a : b; }
|
||||||
static inline unsigned long long guf_clamp_ulong_long(unsigned long long x, unsigned long long min, unsigned long long max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline unsigned long long guf_clamp_ulong_long(unsigned long long x, unsigned long long min, unsigned long long max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
static inline uint8_t guf_min_u8(uint8_t a, uint8_t b) { return a < b ? a : b; }
|
|
||||||
static inline uint8_t guf_max_u8(uint8_t a, uint8_t b) { return a > b ? a : b; }
|
|
||||||
static inline uint8_t guf_clamp_u8(uint8_t x, uint8_t min, uint8_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline uint16_t guf_min_u16(uint16_t a, uint16_t b) { return a < b ? a : b; }
|
|
||||||
static inline uint16_t guf_max_u16(uint16_t a, uint16_t b) { return a > b ? a : b; }
|
|
||||||
static inline uint16_t guf_clamp_u16(uint16_t x, uint16_t min, uint16_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline uint32_t guf_min_u32(uint32_t a, uint32_t b) { return a < b ? a : b; }
|
|
||||||
static inline uint32_t guf_max_u32(uint32_t a, uint32_t b) { return a > b ? a : b; }
|
|
||||||
static inline uint32_t guf_clamp_u32(uint32_t x, uint32_t min, uint32_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline uint64_t guf_min_u64(uint64_t a, uint64_t b) { return a < b ? a : b; }
|
|
||||||
static inline uint64_t guf_max_u64(uint64_t a, uint64_t b) { return a > b ? a : b; }
|
|
||||||
static inline uint64_t guf_clamp_u64(uint64_t x, uint64_t min, uint64_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
|
||||||
|
|
||||||
static inline size_t guf_min_size_t(size_t a, size_t b) { return a < b ? a : b; }
|
static inline size_t guf_min_size_t(size_t a, size_t b) { return a < b ? a : b; }
|
||||||
static inline size_t guf_max_size_t(size_t a, size_t b) { return a > b ? a : b; }
|
static inline size_t guf_max_size_t(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
static inline size_t guf_clamp_size_t(size_t x, size_t min, size_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
static inline size_t guf_clamp_size_t(size_t x, size_t min, size_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline uint_fast8_t guf_min_u8_fast(uint_fast8_t a, uint_fast8_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint_fast8_t guf_max_u8_fast(uint_fast8_t a, uint_fast8_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint_fast8_t guf_clamp_u8_fast(uint_fast8_t x, uint_fast8_t min, uint_fast8_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline uint_fast16_t guf_min_u16_fast(uint_fast16_t a, uint_fast16_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint_fast16_t guf_max_u16_fast(uint_fast16_t a, uint_fast16_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint_fast16_t guf_clamp_u16_fast(uint_fast16_t x, uint_fast16_t min, uint_fast16_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline uint_fast32_t guf_min_u32_fast(uint_fast32_t a, uint_fast32_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint_fast32_t guf_max_u32_fast(uint_fast32_t a, uint_fast32_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint_fast32_t guf_clamp_u32_fast(uint_fast32_t x, uint_fast32_t min, uint_fast32_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
static inline uint_fast64_t guf_min_u64_fast(uint_fast64_t a, uint_fast64_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint_fast64_t guf_max_u64_fast(uint_fast64_t a, uint_fast64_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint_fast64_t guf_clamp_u64_fast(uint_fast64_t x, uint_fast64_t min, uint_fast64_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
|
||||||
|
#ifdef UINT8_MAX
|
||||||
|
static inline uint8_t guf_min_u8(uint8_t a, uint8_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint8_t guf_max_u8(uint8_t a, uint8_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint8_t guf_clamp_u8(uint8_t x, uint8_t min, uint8_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef UINT16_MAX
|
||||||
|
static inline uint16_t guf_min_u16(uint16_t a, uint16_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint16_t guf_max_u16(uint16_t a, uint16_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint16_t guf_clamp_u16(uint16_t x, uint16_t min, uint16_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef UINT32_MAX
|
||||||
|
static inline uint32_t guf_min_u32(uint32_t a, uint32_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint32_t guf_max_u32(uint32_t a, uint32_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint32_t guf_clamp_u32(uint32_t x, uint32_t min, uint32_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef UINT64_MAX
|
||||||
|
static inline uint64_t guf_min_u64(uint64_t a, uint64_t b) { return a < b ? a : b; }
|
||||||
|
static inline uint64_t guf_max_u64(uint64_t a, uint64_t b) { return a > b ? a : b; }
|
||||||
|
static inline uint64_t guf_clamp_u64(uint64_t x, uint64_t min, uint64_t max) { if (x < min) {return min;} if (x > max) {return max;} return x; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// abs functions with signed result (can fail/panic for abs(INT_TYPE_MIN) for platforms with two's complement signed ints; C2X for example guarantees two's complement)
|
// abs functions with signed result (can fail/panic for abs(INT_TYPE_MIN) for platforms with two's complement signed ints; C2X for example guarantees two's complement)
|
||||||
static inline int guf_abs_int(int x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT_MAX == INT_MIN || x > INT_MIN); return -x;} // I would not drink that...
|
// static inline int guf_abs_int(int x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT_MAX == INT_MIN || x > INT_MIN); return -x;} // I would not drink that...
|
||||||
static inline int8_t guf_abs_i8 (int8_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT8_MAX == INT8_MIN || x > INT8_MIN); return -x;}
|
// static inline int8_t guf_abs_i8 (int8_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT8_MAX == INT8_MIN || x > INT8_MIN); return -x;}
|
||||||
static inline int16_t guf_abs_i16(int16_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT16_MAX == INT16_MIN || x > INT16_MIN); return -x;}
|
// static inline int16_t guf_abs_i16(int16_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT16_MAX == INT16_MIN || x > INT16_MIN); return -x;}
|
||||||
static inline int32_t guf_abs_i32(int32_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT32_MAX == INT32_MIN || x > INT32_MIN); return -x;}
|
// static inline int32_t guf_abs_i32(int32_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT32_MAX == INT32_MIN || x > INT32_MIN); return -x;}
|
||||||
static inline int64_t guf_abs_i64(int64_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT64_MAX == INT64_MIN || x > INT64_MIN); return -x;}
|
// static inline int64_t guf_abs_i64(int64_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-INT64_MAX == INT64_MIN || x > INT64_MIN); return -x;}
|
||||||
static inline ptrdiff_t guf_abs_ptrdiff(ptrdiff_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-PTRDIFF_MAX == PTRDIFF_MIN || x > PTRDIFF_MIN); return -x;}
|
// static inline ptrdiff_t guf_abs_ptrdiff(ptrdiff_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(-PTRDIFF_MAX == PTRDIFF_MIN || x > PTRDIFF_MIN); return -x;}
|
||||||
|
|
||||||
// abs functions with unsigned result functions (cannot fail)
|
// abs functions with unsigned result functions (cannot fail)
|
||||||
static inline unsigned guf_uabs_int(int x) {if (x >= 0) {return x;} else if (x == INT_MIN && -INT_MAX != INT_MIN) {return (unsigned)INT_MAX + 1u;} else {return -x;}}
|
static inline unsigned guf_uabs_int(int x) {if (x >= 0) {return x;} else if (x == INT_MIN && -INT_MAX != INT_MIN) {return (unsigned)INT_MAX + 1u;} else {return -x;}}
|
||||||
static inline uint8_t guf_uabs_i8(int8_t x) {if (x >= 0) {return x;} else if (x == INT8_MIN && -INT8_MAX != INT8_MIN) {return (uint8_t)INT8_MAX + 1u;} else {return -x;}}
|
static inline unsigned long guf_uabs_long(long x) {if (x >= 0) {return x;} else if (x == LONG_MIN && -LONG_MAX != LONG_MIN) {return (unsigned long)LONG_MAX + 1u;} else {return -x;}}
|
||||||
static inline uint16_t guf_uabs_i16(int16_t x) {if (x >= 0) {return x;} else if (x == INT16_MIN && -INT16_MAX != INT16_MIN) {return (uint16_t)INT16_MAX + 1u;} else {return -x;}}
|
static inline unsigned long long guf_uabs_long_long(long long x) {if (x >= 0) {return x;} else if (x == LLONG_MIN && -LLONG_MAX != LONG_MIN) {return (unsigned long long)LLONG_MAX + 1u;} else {return -x;}}
|
||||||
static inline uint32_t guf_uabs_i32(int32_t x) {if (x >= 0) {return x;} else if (x == INT32_MIN && -INT32_MAX != INT32_MIN) {return (uint32_t)INT32_MAX + 1u;} else {return -x;}}
|
|
||||||
static inline uint64_t guf_uabs_i64(int64_t x) {if (x >= 0) {return x;} else if (x == INT64_MIN && -INT64_MAX != INT64_MIN) {return (uint64_t)INT64_MAX + 1u;} else {return -x;}}
|
|
||||||
static inline size_t guf_uabs_ptrdiff_t(ptrdiff_t x) {if (x >= 0) {return x;} else if (x == PTRDIFF_MIN && -PTRDIFF_MAX != PTRDIFF_MIN) {return (size_t)PTRDIFF_MAX + 1u;} else {return -x;}}
|
static inline size_t guf_uabs_ptrdiff_t(ptrdiff_t x) {if (x >= 0) {return x;} else if (x == PTRDIFF_MIN && -PTRDIFF_MAX != PTRDIFF_MIN) {return (size_t)PTRDIFF_MAX + 1u;} else {return -x;}}
|
||||||
|
|
||||||
|
#if defined(UINT8_MAX) && defined(INT8_MAX)
|
||||||
|
static inline uint8_t guf_uabs_i8(int8_t x) {if (x >= 0) {return x;} else if (x == INT8_MIN && -INT8_MAX != INT8_MIN) {return (uint8_t)INT8_MAX + 1u;} else {return -x;}}
|
||||||
|
#endif
|
||||||
|
#if defined(UINT16_MAX) && defined(INT16_MAX)
|
||||||
|
static inline uint16_t guf_uabs_i16(int16_t x) {if (x >= 0) {return x;} else if (x == INT16_MIN && -INT16_MAX != INT16_MIN) {return (uint16_t)INT16_MAX + 1u;} else {return -x;}}
|
||||||
|
#endif
|
||||||
|
#if defined(UINT32_MAX) && defined(INT32_MAX)
|
||||||
|
static inline uint32_t guf_uabs_i32(int32_t x) {if (x >= 0) {return x;} else if (x == INT32_MIN && -INT32_MAX != INT32_MIN) {return (uint32_t)INT32_MAX + 1u;} else {return -x;}}
|
||||||
|
#endif
|
||||||
|
#if defined(UINT64_MAX) && defined(INT64_MAX)
|
||||||
|
static inline uint64_t guf_uabs_i64(int64_t x) {if (x >= 0) {return x;} else if (x == INT64_MIN && -INT64_MAX != INT64_MIN) {return (uint64_t)INT64_MAX + 1u;} else {return -x;}}
|
||||||
|
#endif
|
||||||
|
|
||||||
// absdiff functions with unsigned result (cannot fail)
|
// absdiff functions with unsigned result (cannot fail)
|
||||||
static inline unsigned char guf_absdiff_char(char a, char b) {return a > b ? (unsigned char)a - (unsigned char)b : (unsigned char)b - (unsigned char)a;}
|
static inline unsigned char guf_absdiff_char(char a, char b) {return a > b ? (unsigned char)a - (unsigned char)b : (unsigned char)b - (unsigned char)a;}
|
||||||
|
static inline unsigned short guf_absdiff_short(short a, short b) {return a > b ? (unsigned short)a - (unsigned short)b : (unsigned short)b - (unsigned short)a;}
|
||||||
static inline unsigned guf_absdiff_int(int a, int b) {return a > b ? (unsigned)a - (unsigned)b : (unsigned)b - (unsigned)a;}
|
static inline unsigned guf_absdiff_int(int a, int b) {return a > b ? (unsigned)a - (unsigned)b : (unsigned)b - (unsigned)a;}
|
||||||
static inline uint8_t guf_absdiff_i8(int8_t a, int8_t b) {return a > b ? (uint8_t)a - (uint8_t)b : (uint8_t)b - (uint8_t)a;}
|
static inline unsigned long guf_absdiff_long(long a, long b) {return a > b ? (unsigned long)a - (unsigned long)b : (unsigned long)b - (unsigned long)a;}
|
||||||
static inline uint16_t guf_absdiff_i16(int16_t a, int16_t b) {return a > b ? (uint16_t)a - (uint16_t)b : (uint16_t)b - (uint16_t)a;}
|
static inline unsigned long long guf_absdiff_long_long(long long a, long long b) {return a > b ? (unsigned long long)a - (unsigned long long)b : (unsigned long long)b - (unsigned long long)a;}
|
||||||
static inline uint32_t guf_absdiff_i32(int32_t a, int32_t b) {return a > b ? (uint32_t)a - (uint32_t)b : (uint32_t)b - (uint32_t)a;}
|
|
||||||
static inline uint64_t guf_absdiff_i64(int64_t a, int64_t b) {return a > b ? (uint64_t)a - (uint64_t)b : (uint64_t)b - (uint64_t)a;}
|
|
||||||
static inline size_t guf_absdiff_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) {return a > b ? (size_t)a - (size_t)b : (size_t)b - (size_t)a;}
|
static inline size_t guf_absdiff_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) {return a > b ? (size_t)a - (size_t)b : (size_t)b - (size_t)a;}
|
||||||
|
|
||||||
|
static inline uint_fast8_t guf_absdiff_int_fast8_t(int_fast8_t a, int_fast8_t b) {return a > b ? GUF_UWRAP_8( (uint_fast8_t)a - (uint_fast8_t)b) : GUF_UWRAP_8( (uint_fast8_t)b - (uint_fast8_t)a);}
|
||||||
|
static inline uint_fast16_t guf_absdiff_int_fast16_t(int_fast16_t a, int_fast16_t b) {return a > b ? GUF_UWRAP_16((uint_fast16_t)a - (uint_fast16_t)b) : GUF_UWRAP_16((uint_fast16_t)b - (uint_fast16_t)a);}
|
||||||
|
static inline uint_fast32_t guf_absdiff_int_fast32_t(int_fast32_t a, int_fast32_t b) {return a > b ? GUF_UWRAP_32((uint_fast32_t)a - (uint_fast32_t)b) : GUF_UWRAP_32((uint_fast32_t)b - (uint_fast32_t)a);}
|
||||||
|
static inline uint_fast64_t guf_absdiff_int_fast64_t(int_fast64_t a, int_fast64_t b) {return a > b ? GUF_UWRAP_64((uint_fast64_t)a - (uint_fast64_t)b) : GUF_UWRAP_64((uint_fast64_t)b - (uint_fast64_t)a);}
|
||||||
|
|
||||||
|
#if defined(UINT8_MAX) && defined(INT8_MAX)
|
||||||
|
static inline uint8_t guf_absdiff_i8(int8_t a, int8_t b) {return a > b ? (uint8_t)a - (uint8_t)b : (uint8_t)b - (uint8_t)a;}
|
||||||
|
#endif
|
||||||
|
#if defined(UINT16_MAX) && defined(INT16_MAX)
|
||||||
|
static inline uint16_t guf_absdiff_i16(int16_t a, int16_t b) {return a > b ? (uint16_t)a - (uint16_t)b : (uint16_t)b - (uint16_t)a;}
|
||||||
|
#endif
|
||||||
|
#if defined(UINT32_MAX) && defined(INT32_MAX)
|
||||||
|
static inline uint32_t guf_absdiff_i32(int32_t a, int32_t b) {return a > b ? (uint32_t)a - (uint32_t)b : (uint32_t)b - (uint32_t)a;}
|
||||||
|
#endif
|
||||||
|
#if defined(UINT64_MAX) && defined(INT64_MAX)
|
||||||
|
static inline uint64_t guf_absdiff_i64(int64_t a, int64_t b) {return a > b ? (uint64_t)a - (uint64_t)b : (uint64_t)b - (uint64_t)a;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static inline bool guf_add_is_overflow_size_t(size_t a, size_t b)
|
static inline bool guf_add_is_overflow_size_t(size_t a, size_t b)
|
||||||
{
|
{
|
||||||
@ -186,12 +294,24 @@ static inline bool guf_size_calc_safe(ptrdiff_t count, ptrdiff_t sizeof_elem, pt
|
|||||||
|
|
||||||
|
|
||||||
// cf. https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 (last-retrieved 2025-03-19)
|
// cf. https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 (last-retrieved 2025-03-19)
|
||||||
static inline bool guf_is_pow2_u8(uint8_t x) { return x && !(x & (x - 1)); }
|
static inline bool guf_is_pow2_uchar(unsigned char x) { return x && !(x & (x - 1)); }
|
||||||
static inline bool guf_is_pow2_u16(uint16_t x) { return x && !(x & (x - 1)); }
|
static inline bool guf_is_pow2_ushort(unsigned short x) { return x && !(x & (x - 1)); }
|
||||||
static inline bool guf_is_pow2_u32(uint32_t x) { return x && !(x & (x - 1)); }
|
static inline bool guf_is_pow2_unsigned(unsigned x) { return x && !(x & (x - 1)); }
|
||||||
static inline bool guf_is_pow2_u64(uint64_t x) { return x && !(x & (x - 1)); }
|
static inline bool guf_is_pow2_ulong(unsigned long x) { return x && !(x & (x - 1)); }
|
||||||
|
static inline bool guf_is_pow2_ulong_long(unsigned long long x) { return x && !(x & (x - 1)); }
|
||||||
static inline bool guf_is_pow2_size_t(size_t x) { return x && !(x & (x - 1)); }
|
static inline bool guf_is_pow2_size_t(size_t x) { return x && !(x & (x - 1)); }
|
||||||
|
#ifdef UINT8_MAX
|
||||||
|
static inline bool guf_is_pow2_u8(uint8_t x) { return x && !(x & (x - 1)); }
|
||||||
|
#endif
|
||||||
|
#ifdef UINT16_MAX
|
||||||
|
static inline bool guf_is_pow2_u16(uint16_t x) { return x && !(x & (x - 1)); }
|
||||||
|
#endif
|
||||||
|
#ifdef UINT32_MAX
|
||||||
|
static inline bool guf_is_pow2_u32(uint32_t x) { return x && !(x & (x - 1)); }
|
||||||
|
#endif
|
||||||
|
#if UINT64_MAX
|
||||||
|
static inline bool guf_is_pow2_u64(uint64_t x) { return x && !(x & (x - 1)); }
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool guf_nearly_zero_f32(float x, float eps) {return fabsf(x) <= eps;}
|
static bool guf_nearly_zero_f32(float x, float eps) {return fabsf(x) <= eps;}
|
||||||
static bool guf_nearly_one_f32(float x, float eps) {return fabsf(x - 1) <= eps;}
|
static bool guf_nearly_one_f32(float x, float eps) {return fabsf(x - 1) <= eps;}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
438
src/guf_rand.h
438
src/guf_rand.h
@ -26,29 +26,24 @@
|
|||||||
|
|
||||||
// State for xoshiro128** 1.1
|
// State for xoshiro128** 1.1
|
||||||
typedef struct guf_rand32_state {
|
typedef struct guf_rand32_state {
|
||||||
uint32_t s[4]; // Must not be all zero.
|
uint_fast32_t s[4]; // Must not be all zero.
|
||||||
} guf_rand32_state;
|
} guf_rand32_state;
|
||||||
|
|
||||||
// State for xoshiro256** 1.0
|
// State for xoshiro256** 1.0
|
||||||
#ifdef UINT64_MAX
|
|
||||||
typedef struct guf_rand64_state {
|
typedef struct guf_rand64_state {
|
||||||
uint64_t s[4]; // Must not be all zero.
|
uint_fast64_t s[4]; // Must not be all zero.
|
||||||
} guf_rand64_state;
|
} guf_rand64_state;
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GUF_RAND_32_BIT
|
#ifdef GUF_RAND_32_BIT
|
||||||
// Use guf_rand32_state (i.e. xoshiro128** 1.1) as default.
|
// Use guf_rand32_state (i.e. xoshiro128** 1.1) as default.
|
||||||
#define GUF_RAND_MAX UINT32_MAX
|
#define GUF_RAND_MAX GUF_UINT32_MAX
|
||||||
typedef guf_rand32_state guf_randstate;
|
typedef guf_rand32_state guf_randstate;
|
||||||
typedef uint32_t guf_rand_seed_t;
|
typedef uint_fast32_t guf_rand_seed_t;
|
||||||
#else
|
#else
|
||||||
// Use guf_rand64_state (i.e. xoshiro256** 1.0) as default.
|
// Use guf_rand64_state (i.e. xoshiro256** 1.0) as default.
|
||||||
#ifndef UINT64_MAX
|
#define GUF_RAND_MAX GUF_UINT64_MAX
|
||||||
#error "guf_rand.h: Platform does not support uint64_t (define GUF_RAND_32_BIT to fix)"
|
|
||||||
#endif
|
|
||||||
#define GUF_RAND_MAX UINT64_MAX
|
|
||||||
typedef guf_rand64_state guf_randstate;
|
typedef guf_rand64_state guf_randstate;
|
||||||
typedef uint64_t guf_rand_seed_t;
|
typedef uint_fast64_t guf_rand_seed_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -60,76 +55,59 @@ typedef struct guf_rand32_state {
|
|||||||
(If you want to initialise the guf_randstate struct manually, you have to ensure yourself the four state-integers aren't all zero.)
|
(If you want to initialise the guf_randstate struct manually, you have to ensure yourself the four state-integers aren't all zero.)
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS void guf_randstate_init(guf_randstate *state, guf_rand_seed_t seed);
|
GUF_RAND_KWRDS void guf_randstate_init(guf_randstate *state, guf_rand_seed_t seed);
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS void guf_rand64_state_init(guf_rand64_state *state, uint_fast64_t seed);
|
||||||
GUF_RAND_KWRDS void guf_rand64_state_init(guf_rand64_state *state, uint64_t seed);
|
GUF_RAND_KWRDS void guf_rand32_state_init(guf_rand32_state *state, uint_fast32_t seed);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS void guf_rand32_state_init(guf_rand32_state *state, uint32_t seed);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_randstate_jump(state)
|
- guf_randstate_jump(state)
|
||||||
-> void; advance the rng-state as if 2^128 (or 2^64 for rand32_state) calls to guf_rand_u32 had occured.
|
-> void; advance the rng-state as if 2^128 (or 2^64 for rand32_state) calls to guf_rand_u32 had occured.
|
||||||
Can be used to generate 2^128 (or 2^64 for rand32_state) non-overlapping subsequences for parallel computations.
|
Can be used to generate 2^128 (or 2^64 for rand32_state) non-overlapping subsequences for parallel computations.
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS void guf_randstate_jump(guf_randstate *state); // Equivalent to 2^128 (or 2^64) calls to guf_rand_u32
|
GUF_RAND_KWRDS void guf_randstate_jump(guf_randstate *state); // Equivalent to 2^128 (or 2^64) calls to guf_rand_u32/u64
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS void guf_rand64_state_jump(guf_rand64_state *state); // Equivalent to 2^128 calls to guf_rand64_u64
|
GUF_RAND_KWRDS void guf_rand64_state_jump(guf_rand64_state *state); // Equivalent to 2^128 calls to guf_rand64_u64
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS void guf_rand32_state_jump(guf_rand32_state *state); // Equivalent to 2^64 calls to guf_rand32_u32
|
GUF_RAND_KWRDS void guf_rand32_state_jump(guf_rand32_state *state); // Equivalent to 2^64 calls to guf_rand32_u32
|
||||||
|
|
||||||
|
|
||||||
// Uniform distributions in default ranges:
|
// Uniform distributions in default ranges:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_rand_splitmix64(state) -> uint64_t in range [0, UINT64_MAX]
|
- guf_rand_splitmix64(state) -> u64 in range [0, UINT64_MAX]
|
||||||
(Very simple rng with only 64-bits of state; used for "scrambling" 64-bit seeds in guf_randstate_init.)
|
(Very simple rng with only 64-bits of state; used for "scrambling" 64-bit seeds in guf_randstate_init.)
|
||||||
- guf_rand_splitmix32(state) -> uint32_t in range [0, UINT32_MAX]
|
- guf_rand_splitmix32(state) -> u32 in range [0, UINT32_MAX]
|
||||||
(Very simple rng with only 32-bits of state; used for "scrambling" 32-bit seeds in guf_randstate_init.)
|
(Very simple rng with only 32-bits of state; used for "scrambling" 32-bit seeds in guf_randstate_init.)
|
||||||
*/
|
*/
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS uint_fast64_t guf_rand_splitmix64(uint_fast64_t *state);
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand_splitmix64(uint64_t *state);
|
GUF_RAND_KWRDS uint_fast32_t guf_rand_splitmix32(uint_fast32_t *state);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand_splitmix32(uint32_t *state);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_rand_u32(state) -> uint32_t in range [0, UINT32_MAX]
|
- guf_rand_u32(state) -> u32 in range [0, UINT32_MAX]
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand_u32(guf_randstate *state);
|
GUF_RAND_KWRDS uint_fast32_t guf_rand_u32(guf_randstate *state);
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS uint_fast32_t guf_rand64_u32(guf_rand64_state *state);
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand64_u32(guf_rand64_state *state);
|
GUF_RAND_KWRDS uint_fast32_t guf_rand32_u32(guf_rand32_state *state);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand32_u32(guf_rand32_state *state);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_rand_u64(state) -> uint64_t (or uint_least64_t) in range [0, UINT64_MAX]
|
- guf_rand_u64(state) -> uint64_t (or uint_least64_t) in range [0, UINT64_MAX]
|
||||||
NOTE: May be slow on 32-bit platforms.
|
NOTE: May be slow on 32-bit platforms.
|
||||||
NOTE: If uint64_t is not available (optional according to the standards), use uint_least64_t (always available in C99 and above).
|
NOTE: If uint64_t is not available (optional according to the standards), use uint_least64_t (always available in C99 and above).
|
||||||
*/
|
*/
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS uint_fast64_t guf_rand_u64(guf_randstate *state);
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand_u64(guf_randstate *state);
|
GUF_RAND_KWRDS uint_fast64_t guf_rand32_u64(guf_rand32_state *state);
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand32_u64(guf_rand32_state *state);
|
GUF_RAND_KWRDS uint_fast64_t guf_rand64_u64(guf_rand64_state *state);
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand64_u64(guf_rand64_state *state);
|
|
||||||
#else
|
|
||||||
GUF_RAND_KWRDS uint_least64_t guf_rand_u64(guf_randstate *state)
|
|
||||||
GUF_RAND_KWRDS uint_least64_t guf_rand32_u64(guf_rand32_state *state);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_rand_f64(state) -> double in range [0.0, 1.0)
|
- guf_rand_f64(state) -> double in range [0.0, 1.0)
|
||||||
NOTE: May be slow on 32-bit platforms (as it calls guf_rand_u64)
|
NOTE: May be slow on 32-bit platforms (as it calls guf_rand_u64)
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS double guf_rand_f64(guf_randstate *state);
|
GUF_RAND_KWRDS double guf_rand_f64(guf_randstate *state);
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS double guf_rand64_f64(guf_rand64_state *state);
|
GUF_RAND_KWRDS double guf_rand64_f64(guf_rand64_state *state);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS double guf_rand32_f64(guf_rand32_state *state);
|
GUF_RAND_KWRDS double guf_rand32_f64(guf_rand32_state *state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_rand_f32(state) -> float in range [0.f, 1.f)
|
- guf_rand_f32(state) -> float in range [0.f, 1.f)
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS float guf_rand_f32(guf_randstate *state);
|
GUF_RAND_KWRDS float guf_rand_f32(guf_randstate *state);
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS float guf_rand64_f32(guf_rand64_state *state);
|
GUF_RAND_KWRDS float guf_rand64_f32(guf_rand64_state *state);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS float guf_rand32_f32(guf_rand32_state *state);
|
GUF_RAND_KWRDS float guf_rand32_f32(guf_rand32_state *state);
|
||||||
|
|
||||||
|
|
||||||
@ -142,39 +120,34 @@ GUF_RAND_KWRDS float guf_rand32_f32(guf_rand32_state *state);
|
|||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float end);
|
GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float end);
|
||||||
GUF_RAND_KWRDS double guf_randrange_f64(guf_randstate *state, double min, double end);
|
GUF_RAND_KWRDS double guf_randrange_f64(guf_randstate *state, double min, double end);
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS float guf_rand64_range_f32(guf_rand64_state *state, float min, float end);
|
GUF_RAND_KWRDS float guf_rand64_range_f32(guf_rand64_state *state, float min, float end);
|
||||||
GUF_RAND_KWRDS double guf_rand64_range_f64(guf_rand64_state *state, double min, double end);
|
GUF_RAND_KWRDS double guf_rand64_range_f64(guf_rand64_state *state, double min, double end);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS float guf_rand32_range_f32(guf_rand32_state *state, float min, float end);
|
GUF_RAND_KWRDS float guf_rand32_range_f32(guf_rand32_state *state, float min, float end);
|
||||||
GUF_RAND_KWRDS double guf_rand32_range_f64(guf_rand32_state *state, double min, double end);
|
GUF_RAND_KWRDS double guf_rand32_range_f64(guf_rand32_state *state, double min, double end);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_randrange_i32(state, min, max) -> int32_t in range [min, max] (contrary to the float equivalents, max *is* inclusive)
|
- guf_randrange_i32(state, min, max) -> i32 in range [min, max] (contrary to the float equivalents, max *is* inclusive)
|
||||||
- guf_randrange_u32(state, min, max) -> uint32_t in range [min, max] (contrary to the float equivalents, max *is* inclusive)
|
- guf_randrange_u32(state, min, max) -> u32 in range [min, max] (contrary to the float equivalents, max *is* inclusive)
|
||||||
NOTE: guf_randrange_u32 may be slow on 32-bit platforms (as it calls guf_rand_f64).
|
NOTE: guf_randrange_u32 may be slow on 32-bit platforms (as it calls guf_rand_f64).
|
||||||
This does not apply to guf_randrange_i32 (as it doesn't call guf_rand_f64).
|
This does not apply to guf_randrange_i32 (as it doesn't call guf_rand_f64).
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int32_t max);
|
GUF_RAND_KWRDS int_fast32_t guf_randrange_i32(guf_randstate *state, int_fast32_t min, int_fast32_t max);
|
||||||
GUF_RAND_KWRDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, uint32_t max); // NOTE: may be slow on 32-bit platforms.
|
GUF_RAND_KWRDS uint_fast32_t guf_randrange_u32(guf_randstate *state, uint_fast32_t min, uint_fast32_t max); // NOTE: may be slow on 32-bit platforms (as it calls guf_rand_f64).
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS int32_t guf_rand64_range_i32(guf_rand64_state *state, int32_t min, int32_t max);
|
GUF_RAND_KWRDS int_fast32_t guf_rand64_range_i32(guf_rand64_state *state, int_fast32_t min, int_fast32_t max);
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand64_range_u32(guf_rand64_state *state, uint32_t min, uint32_t max);
|
GUF_RAND_KWRDS uint_fast32_t guf_rand64_range_u32(guf_rand64_state *state, uint_fast32_t min, uint_fast32_t max);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS int32_t guf_rand32_range_i32(guf_rand32_state *state, int32_t min, int32_t max);
|
GUF_RAND_KWRDS int_fast32_t guf_rand32_range_i32(guf_rand32_state *state, int_fast32_t min, int_fast32_t max);
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand32_range_u32(guf_rand32_state *state, uint32_t min, uint32_t max); // NOTE: may be slow on 32-bit platforms.
|
GUF_RAND_KWRDS uint_fast32_t guf_rand32_range_u32(guf_rand32_state *state, uint_fast32_t min, uint_fast32_t max); // NOTE: may be slow on 32-bit platforms (as it calls guf_rand_f64).
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- guf_randrange_i64(state, min, max) -> int64_t in range [min, max] (contrary to the float equivalents, max *is* inclusive)
|
- guf_randrange_i64(state, min, max) -> int64_t in range [min, max] (contrary to the float equivalents, max *is* inclusive)
|
||||||
NOTE: The Generic version is only available if GUF_RAND_32_BIT is undefined and the platform supports uint64_t.
|
|
||||||
(The specific guf_rand64_range_i64 version is available as long as the platform supports uint64_t.)
|
|
||||||
*/
|
*/
|
||||||
#if defined(UINT64_MAX) && !defined(GUF_RAND_32_BIT)
|
GUF_RAND_KWRDS int_fast64_t guf_randrange_i64(guf_randstate *state, int_fast64_t min, int_fast64_t max);
|
||||||
GUF_RAND_KWRDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int64_t max);
|
GUF_RAND_KWRDS int_fast64_t guf_rand64_range_i64(guf_rand64_state *state, int_fast64_t min, int_fast64_t max);
|
||||||
#endif
|
GUF_RAND_KWRDS int_fast64_t guf_rand32_range_i64(guf_rand32_state *state, int_fast64_t min, int_fast64_t max);
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS int64_t guf_rand64_range_i64(guf_rand64_state *state, int64_t min, int64_t max);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Bernoulli-trials:
|
// Bernoulli-trials:
|
||||||
|
|
||||||
@ -187,11 +160,11 @@ GUF_RAND_KWRDS uint32_t guf_rand32_range_u32(guf_rand32_state *state, uint32_t m
|
|||||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p);
|
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p);
|
||||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p);
|
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p);
|
||||||
GUF_RAND_KWRDS bool guf_rand_flip(guf_randstate *state);
|
GUF_RAND_KWRDS bool guf_rand_flip(guf_randstate *state);
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f32(guf_rand64_state *state, float p);
|
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f32(guf_rand64_state *state, float p);
|
||||||
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f64(guf_rand64_state *state, double p);
|
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f64(guf_rand64_state *state, double p);
|
||||||
GUF_RAND_KWRDS bool guf_rand64_flip(guf_rand64_state *state);
|
GUF_RAND_KWRDS bool guf_rand64_flip(guf_rand64_state *state);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS bool guf_rand32_bernoulli_trial_f32(guf_rand32_state *state, float p);
|
GUF_RAND_KWRDS bool guf_rand32_bernoulli_trial_f32(guf_rand32_state *state, float p);
|
||||||
GUF_RAND_KWRDS bool guf_rand32_bernoulli_trial_f64(guf_rand32_state *state, double p);
|
GUF_RAND_KWRDS bool guf_rand32_bernoulli_trial_f64(guf_rand32_state *state, double p);
|
||||||
GUF_RAND_KWRDS bool guf_rand32_flip(guf_rand32_state *state);
|
GUF_RAND_KWRDS bool guf_rand32_flip(guf_rand32_state *state);
|
||||||
@ -209,12 +182,12 @@ GUF_RAND_KWRDS void guf_rand_normal_sample_f64(guf_randstate *state, double mean
|
|||||||
GUF_RAND_KWRDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
GUF_RAND_KWRDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
||||||
GUF_RAND_KWRDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev);
|
GUF_RAND_KWRDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev);
|
||||||
GUF_RAND_KWRDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev);
|
GUF_RAND_KWRDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev);
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS void guf_rand64_normal_sample_f32(guf_rand64_state *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
GUF_RAND_KWRDS void guf_rand64_normal_sample_f32(guf_rand64_state *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
||||||
GUF_RAND_KWRDS void guf_rand64_normal_sample_f64(guf_rand64_state *state, double mean, double std_dev, double *result, ptrdiff_t n);
|
GUF_RAND_KWRDS void guf_rand64_normal_sample_f64(guf_rand64_state *state, double mean, double std_dev, double *result, ptrdiff_t n);
|
||||||
GUF_RAND_KWRDS float guf_rand64_normal_sample_one_f32(guf_rand64_state *state, float mean, float std_dev);
|
GUF_RAND_KWRDS float guf_rand64_normal_sample_one_f32(guf_rand64_state *state, float mean, float std_dev);
|
||||||
GUF_RAND_KWRDS double guf_rand64_normal_sample_one_f64(guf_rand64_state *state, double mean, double std_dev);
|
GUF_RAND_KWRDS double guf_rand64_normal_sample_one_f64(guf_rand64_state *state, double mean, double std_dev);
|
||||||
#endif
|
|
||||||
GUF_RAND_KWRDS void guf_rand32_normal_sample_f32(guf_rand32_state *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
GUF_RAND_KWRDS void guf_rand32_normal_sample_f32(guf_rand32_state *state, float mean, float std_dev, float *result, ptrdiff_t n);
|
||||||
GUF_RAND_KWRDS void guf_rand32_normal_sample_f64(guf_rand32_state *state, double mean, double std_dev, double *result, ptrdiff_t n);
|
GUF_RAND_KWRDS void guf_rand32_normal_sample_f64(guf_rand32_state *state, double mean, double std_dev, double *result, ptrdiff_t n);
|
||||||
GUF_RAND_KWRDS float guf_rand32_normal_sample_one_f32(guf_rand32_state *state, float mean, float std_dev);
|
GUF_RAND_KWRDS float guf_rand32_normal_sample_one_f32(guf_rand32_state *state, float mean, float std_dev);
|
||||||
@ -222,6 +195,8 @@ GUF_RAND_KWRDS double guf_rand32_normal_sample_one_f64(guf_rand32_state *state,
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// #define GUF_RAND_IMPL_STATIC /* DEBUG */
|
||||||
|
|
||||||
#if defined(GUF_RAND_IMPL) || defined(GUF_RAND_IMPL_STATIC)
|
#if defined(GUF_RAND_IMPL) || defined(GUF_RAND_IMPL_STATIC)
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@ -231,35 +206,34 @@ GUF_RAND_KWRDS double guf_rand32_normal_sample_one_f64(guf_rand32_state *state,
|
|||||||
#define GUF_MATH_CKDINT_IMPL_STATIC
|
#define GUF_MATH_CKDINT_IMPL_STATIC
|
||||||
#include "guf_math_ckdint.h"
|
#include "guf_math_ckdint.h"
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
/*
|
/*
|
||||||
splitmix64 written in 2015 by Sebastiano Vigna (vigna@acm.org) (released as public domain)
|
splitmix64 written in 2015 by Sebastiano Vigna (vigna@acm.org) (released as public domain)
|
||||||
cf. https://prng.di.unimi.it/splitmix64.c (last-retrieved 2025-02-11)
|
cf. https://prng.di.unimi.it/splitmix64.c (last-retrieved 2025-02-11)
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand_splitmix64(uint64_t *state)
|
GUF_RAND_KWRDS uint_fast64_t guf_rand_splitmix64(uint_fast64_t *state)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(state);
|
GUF_ASSERT(state);
|
||||||
uint64_t z = ((*state) += 1u * 0x9e3779b97f4a7c15);
|
*state = GUF_UWRAP_64(*state);
|
||||||
z = (z ^ (z >> 30u)) * 0xbf58476d1ce4e5b9;
|
uint_fast64_t z = ( *state = GUF_UWRAP_64(*state + 0x9e3779b97f4a7c15ull) );
|
||||||
z = (z ^ (z >> 27u)) * 0x94d049bb133111eb;
|
z = GUF_UWRAP_64( GUF_UWRAP_64(z ^ (z >> 30u)) * 0xbf58476d1ce4e5b9ull );
|
||||||
return z ^ (z >> 31u);
|
z = GUF_UWRAP_64( GUF_UWRAP_64(z ^ (z >> 27u)) * 0x94d049bb133111ebull );
|
||||||
|
return GUF_UWRAP_64(z ^ (z >> 31u));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
splitmix32 written in 2016 by Kaito Udagawa (released under CC0 <http://creativecommons.org/publicdomain/zero/1.0/>)
|
splitmix32 written in 2016 by Kaito Udagawa (released under CC0 <http://creativecommons.org/publicdomain/zero/1.0/>)
|
||||||
cf. https://github.com/umireon/my-random-stuff/blob/master/xorshift/splitmix32.c (last-retrieved 2025-03-28)
|
cf. https://github.com/umireon/my-random-stuff/blob/master/xorshift/splitmix32.c (last-retrieved 2025-03-28)
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand_splitmix32(uint32_t *state)
|
GUF_RAND_KWRDS uint_fast32_t guf_rand_splitmix32(uint_fast32_t *state)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(state);
|
GUF_ASSERT(state);
|
||||||
uint32_t z = (*state += 1u * 0x9e3779b9);
|
uint_fast32_t z = ( *state = GUF_UWRAP_32(*state + 0x9e3779b9ul) );
|
||||||
z = (z ^ (z >> 16u)) * 0x85ebca6b;
|
z = GUF_UWRAP_32( GUF_UWRAP_32(z ^ (z >> 16u)) * 0x85ebca6bul );
|
||||||
z = (z ^ (z >> 13u)) * 0xc2b2ae35;
|
z = GUF_UWRAP_32( GUF_UWRAP_32(z ^ (z >> 13u)) * 0xc2b2ae35ul );
|
||||||
return z ^ (z >> 16u);
|
return GUF_UWRAP_32(z ^ (z >> 16u));
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_RAND_KWRDS void guf_rand32_state_init(guf_rand32_state *state, uint32_t seed)
|
GUF_RAND_KWRDS void guf_rand32_state_init(guf_rand32_state *state, uint_fast32_t seed)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < GUF_ARR_SIZE(state->s); ++i) {
|
for (size_t i = 0; i < GUF_ARR_SIZE(state->s); ++i) {
|
||||||
state->s[i] = guf_rand_splitmix32(&seed);
|
state->s[i] = guf_rand_splitmix32(&seed);
|
||||||
@ -273,8 +247,7 @@ GUF_RAND_KWRDS void guf_rand32_state_init(guf_rand32_state *state, uint32_t seed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS void guf_rand64_state_init(guf_rand64_state *state, uint_fast64_t seed)
|
||||||
GUF_RAND_KWRDS void guf_rand64_state_init(guf_rand64_state *state, uint64_t seed)
|
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < GUF_ARR_SIZE(state->s); ++i) {
|
for (size_t i = 0; i < GUF_ARR_SIZE(state->s); ++i) {
|
||||||
state->s[i] = guf_rand_splitmix64(&seed);
|
state->s[i] = guf_rand_splitmix64(&seed);
|
||||||
@ -287,7 +260,6 @@ GUF_RAND_KWRDS void guf_rand32_state_init(guf_rand32_state *state, uint32_t seed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS void guf_randstate_init(guf_randstate *state, guf_rand_seed_t seed)
|
GUF_RAND_KWRDS void guf_randstate_init(guf_randstate *state, guf_rand_seed_t seed)
|
||||||
{
|
{
|
||||||
@ -298,7 +270,7 @@ GUF_RAND_KWRDS void guf_randstate_init(guf_randstate *state, guf_rand_seed_t see
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand32_u32(guf_rand32_state *state)
|
GUF_RAND_KWRDS uint_fast32_t guf_rand32_u32(guf_rand32_state *state)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(state);
|
GUF_ASSERT(state);
|
||||||
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
||||||
@ -306,25 +278,30 @@ GUF_RAND_KWRDS uint32_t guf_rand32_u32(guf_rand32_state *state)
|
|||||||
xoshiro128** 1.1 (public domain) written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
xoshiro128** 1.1 (public domain) written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||||
cf. https://prng.di.unimi.it/xoshiro128starstar.c (last-retrieved 2025-02-11)
|
cf. https://prng.di.unimi.it/xoshiro128starstar.c (last-retrieved 2025-02-11)
|
||||||
*/
|
*/
|
||||||
const uint32_t result = guf_rotl_u32(state->s[1] * 5u, 7) * 9u;
|
const uint_fast32_t result = GUF_UWRAP_32( guf_rotl32_uint_fast32_t(state->s[1] * 5u, 7) * 9u );
|
||||||
const uint32_t t = state->s[1] << 9u;
|
const uint_fast32_t t = GUF_UWRAP_32( state->s[1] << 9u );
|
||||||
|
|
||||||
state->s[2] ^= state->s[0];
|
state->s[2] ^= state->s[0];
|
||||||
state->s[3] ^= state->s[1];
|
state->s[3] ^= state->s[1];
|
||||||
state->s[1] ^= state->s[2];
|
state->s[1] ^= state->s[2];
|
||||||
state->s[0] ^= state->s[3];
|
state->s[0] ^= state->s[3];
|
||||||
state->s[2] ^= t;
|
state->s[2] ^= t;
|
||||||
state->s[3] = guf_rotl_u32(state->s[3], 11);
|
state->s[3] = guf_rotl32_uint_fast32_t(state->s[3], 11);
|
||||||
|
|
||||||
|
state->s[0] = GUF_UWRAP_32(state->s[0]);
|
||||||
|
state->s[1] = GUF_UWRAP_32(state->s[1]);
|
||||||
|
state->s[2] = GUF_UWRAP_32(state->s[2]);
|
||||||
|
state->s[3] = GUF_UWRAP_32(state->s[3]);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS uint_fast32_t guf_rand64_u32(guf_rand64_state *state)
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand64_u32(guf_rand64_state *state)
|
|
||||||
{
|
{
|
||||||
return (uint32_t)(guf_rand64_u64(state) >> 32u);
|
return (uint_fast32_t)GUF_UWRAP_32( (guf_rand64_u64(state) >> 32u) );
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand_u32(guf_randstate *state)
|
GUF_RAND_KWRDS uint_fast32_t guf_rand_u32(guf_randstate *state)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(state);
|
GUF_ASSERT(state);
|
||||||
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
||||||
@ -336,8 +313,7 @@ GUF_RAND_KWRDS uint32_t guf_rand_u32(guf_randstate *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS uint_fast64_t guf_rand64_u64(guf_rand64_state *state)
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand64_u64(guf_rand64_state *state)
|
|
||||||
{
|
{
|
||||||
GUF_ASSERT(state);
|
GUF_ASSERT(state);
|
||||||
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
||||||
@ -345,41 +321,37 @@ GUF_RAND_KWRDS uint32_t guf_rand_u32(guf_randstate *state)
|
|||||||
xoshiro256** 1.0 (public domain) written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
xoshiro256** 1.0 (public domain) written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
|
||||||
cf. https://prng.di.unimi.it/xoshiro256starstar.c (last-retrieved 2025-02-11)
|
cf. https://prng.di.unimi.it/xoshiro256starstar.c (last-retrieved 2025-02-11)
|
||||||
*/
|
*/
|
||||||
const uint64_t result = guf_rotl_u64(state->s[1] * 5u, 7) * 9u;
|
const uint_fast64_t result = GUF_UWRAP_64( guf_rotl64_uint_fast64_t(state->s[1] * 5u, 7) * 9u );
|
||||||
const uint64_t t = state->s[1] << 17u;
|
const uint_fast64_t t = GUF_UWRAP_64( state->s[1] << 17u );
|
||||||
|
|
||||||
state->s[2] ^= state->s[0];
|
state->s[2] ^= state->s[0];
|
||||||
state->s[3] ^= state->s[1];
|
state->s[3] ^= state->s[1];
|
||||||
state->s[1] ^= state->s[2];
|
state->s[1] ^= state->s[2];
|
||||||
state->s[0] ^= state->s[3];
|
state->s[0] ^= state->s[3];
|
||||||
state->s[2] ^= t;
|
state->s[2] ^= t;
|
||||||
state->s[3] = guf_rotl_u64(state->s[3], 45);
|
state->s[3] = guf_rotl64_uint_fast64_t(state->s[3], 45);
|
||||||
|
|
||||||
|
state->s[0] = GUF_UWRAP_64(state->s[0]);
|
||||||
|
state->s[1] = GUF_UWRAP_64(state->s[1]);
|
||||||
|
state->s[2] = GUF_UWRAP_64(state->s[2]);
|
||||||
|
state->s[3] = GUF_UWRAP_64(state->s[3]);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS uint_fast64_t guf_rand32_u64(guf_rand32_state *state)
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand32_u64(guf_rand32_state *state)
|
|
||||||
#else
|
|
||||||
GUF_RAND_KWRDS uint_least64_t guf_rand32_u64(guf_rand32_state *state)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
GUF_ASSERT(state);
|
GUF_ASSERT(state);
|
||||||
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
GUF_ASSERT(state->s[0] || state->s[1] || state->s[2] || state->s[3]);
|
||||||
const uint32_t lower_bits = guf_rand32_u32(state);
|
const uint_fast32_t lower_bits = guf_rand32_u32(state);
|
||||||
const uint32_t upper_bits = guf_rand32_u32(state);
|
const uint_fast32_t upper_bits = guf_rand32_u32(state);
|
||||||
#ifdef UINT64_MAX
|
GUF_ASSERT( lower_bits <= GUF_UINT32_MAX && upper_bits <= GUF_UINT32_MAX );
|
||||||
return ((uint64_t)upper_bits << 32u) | (uint64_t)lower_bits; // TODO: not sure if that's a good idea...
|
GUF_ASSERT( ( ((uint_fast64_t)upper_bits << 32u) | (uint_fast64_t)lower_bits ) <= GUF_UINT32_MAX);
|
||||||
#else
|
return ((uint_fast64_t)upper_bits << 32u) | (uint_fast64_t)lower_bits; // TODO: not sure if that's a good idea...
|
||||||
return ((uint_least64_t)upper_bits << 32u) | (uint_least64_t)lower_bits; // TODO: not sure if that's a good idea...
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GUF_RAND_KWRDS uint_fast64_t guf_rand_u64(guf_randstate *state)
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS uint64_t guf_rand_u64(guf_randstate *state)
|
|
||||||
#else
|
|
||||||
GUF_RAND_KWRDS uint_least64_t guf_rand_u64(guf_randstate *state)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#ifdef GUF_RAND_32_BIT
|
#ifdef GUF_RAND_32_BIT
|
||||||
return guf_rand32_u64(state);
|
return guf_rand32_u64(state);
|
||||||
@ -395,59 +367,63 @@ GUF_RAND_KWRDS uint_least64_t guf_rand_u64(guf_randstate *state)
|
|||||||
GUF_RAND_KWRDS void guf_rand32_state_jump(guf_rand32_state *state)
|
GUF_RAND_KWRDS void guf_rand32_state_jump(guf_rand32_state *state)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(state);
|
GUF_ASSERT(state);
|
||||||
static const uint32_t JUMP[] = { 0x8764000b, 0xf542d2d3, 0x6fa035c3, 0x77f2db5b };
|
static const uint_fast32_t JUMP[] = { 0x8764000b, 0xf542d2d3, 0x6fa035c3, 0x77f2db5b };
|
||||||
uint32_t s0 = 0;
|
uint_fast32_t s0 = 0;
|
||||||
uint32_t s1 = 0;
|
uint_fast32_t s1 = 0;
|
||||||
uint32_t s2 = 0;
|
uint_fast32_t s2 = 0;
|
||||||
uint32_t s3 = 0;
|
uint_fast32_t s3 = 0;
|
||||||
for (size_t i = 0; i < sizeof JUMP / sizeof *JUMP; ++i) {
|
for (size_t i = 0; i < sizeof JUMP / sizeof *JUMP; ++i) {
|
||||||
for (int b = 0; b < 32; ++b) {
|
for (int b = 0; b < 32; ++b) {
|
||||||
if (JUMP[i] & UINT32_C(1) << b) {
|
if (1u * JUMP[i] & UINT32_C(1) << b) {
|
||||||
s0 ^= state->s[0];
|
s0 ^= state->s[0];
|
||||||
s1 ^= state->s[1];
|
s1 ^= state->s[1];
|
||||||
s2 ^= state->s[2];
|
s2 ^= state->s[2];
|
||||||
s3 ^= state->s[3];
|
s3 ^= state->s[3];
|
||||||
|
s0 = GUF_UWRAP_32(s0);
|
||||||
|
s1 = GUF_UWRAP_32(s1);
|
||||||
|
s2 = GUF_UWRAP_32(s2);
|
||||||
|
s3 = GUF_UWRAP_32(s3);
|
||||||
}
|
}
|
||||||
guf_rand32_u32(state);
|
guf_rand32_u32(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state->s[0] = s0;
|
state->s[0] = GUF_UWRAP_32(s0);
|
||||||
state->s[1] = s1;
|
state->s[1] = GUF_UWRAP_32(s1);
|
||||||
state->s[2] = s2;
|
state->s[2] = GUF_UWRAP_32(s2);
|
||||||
state->s[3] = s3;
|
state->s[3] = GUF_UWRAP_32(s3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
/*
|
/*
|
||||||
Equivalent to 2^128 calls to guf_rand64_u64(); can be used to generate 2^128
|
Equivalent to 2^128 calls to guf_rand64_u64(); can be used to generate 2^128
|
||||||
non-overlapping subsequences for parallel computations.
|
non-overlapping subsequences for parallel computations.
|
||||||
*/
|
*/
|
||||||
GUF_RAND_KWRDS void guf_rand64_state_jump(guf_rand64_state *state)
|
GUF_RAND_KWRDS void guf_rand64_state_jump(guf_rand64_state *state)
|
||||||
{
|
{
|
||||||
static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };
|
static const uint_fast64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };
|
||||||
uint64_t s0 = 0;
|
uint_fast64_t s0 = 0;
|
||||||
uint64_t s1 = 0;
|
uint_fast64_t s1 = 0;
|
||||||
uint64_t s2 = 0;
|
uint_fast64_t s2 = 0;
|
||||||
uint64_t s3 = 0;
|
uint_fast64_t s3 = 0;
|
||||||
for (size_t i = 0; i < sizeof JUMP / sizeof *JUMP; ++i) {
|
for (size_t i = 0; i < sizeof JUMP / sizeof *JUMP; ++i) {
|
||||||
for (int b = 0; b < 64; ++b) {
|
for (int b = 0; b < 64; ++b) {
|
||||||
if (JUMP[i] & UINT64_C(1) << b) {
|
if (1u * JUMP[i] & UINT64_C(1) << b) {
|
||||||
s0 ^= state->s[0];
|
s0 ^= state->s[0];
|
||||||
s1 ^= state->s[1];
|
s1 ^= state->s[1];
|
||||||
s2 ^= state->s[2];
|
s2 ^= state->s[2];
|
||||||
s3 ^= state->s[3];
|
s3 ^= state->s[3];
|
||||||
|
s0 = GUF_UWRAP_64(s0);
|
||||||
|
s1 = GUF_UWRAP_64(s1);
|
||||||
|
s2 = GUF_UWRAP_64(s2);
|
||||||
|
s3 = GUF_UWRAP_64(s3);
|
||||||
}
|
}
|
||||||
guf_rand64_u64(state);
|
guf_rand64_u64(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state->s[0] = s0;
|
state->s[0] = GUF_UWRAP_64(s0);
|
||||||
state->s[1] = s1;
|
state->s[1] = GUF_UWRAP_64(s1);
|
||||||
state->s[2] = s2;
|
state->s[2] = GUF_UWRAP_64(s2);
|
||||||
state->s[3] = s3;
|
state->s[3] = GUF_UWRAP_64(s3);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Equivalent to 2^128 calls to guf_rand() (or 2^64 calls if GUF_RAND_32_BIT); it can be used to generate 2^128 (or 2^64)
|
Equivalent to 2^128 calls to guf_rand() (or 2^64 calls if GUF_RAND_32_BIT); it can be used to generate 2^128 (or 2^64)
|
||||||
@ -463,13 +439,12 @@ GUF_RAND_KWRDS void guf_randstate_jump(guf_randstate *state)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS double guf_rand64_f64(guf_rand64_state *state)
|
GUF_RAND_KWRDS double guf_rand64_f64(guf_rand64_state *state)
|
||||||
{
|
{
|
||||||
// cf. https://prng.di.unimi.it/ and https://dotat.at/@/2023-06-23-random-double.html (last-retrieved 2025-02-11)
|
// cf. https://prng.di.unimi.it/ and https://dotat.at/@/2023-06-23-random-double.html (last-retrieved 2025-02-11)
|
||||||
return (guf_rand64_u64(state) >> 11u) * 0x1.0p-53; // 11 == 64 - 53 (double has a 53-bit mantissa/significand)
|
return (guf_rand64_u64(state) >> 11u) * 0x1.0p-53; // 11 == 64 - 53 (double has a 53-bit mantissa/significand)
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS double guf_rand32_f64(guf_rand32_state *state)
|
GUF_RAND_KWRDS double guf_rand32_f64(guf_rand32_state *state)
|
||||||
{
|
{
|
||||||
@ -484,12 +459,11 @@ GUF_RAND_KWRDS double guf_rand_f64(guf_randstate *state)
|
|||||||
return (guf_rand_u64(state) >> 11u) * 0x1.0p-53; // 11 == 64 - 53 (double has a 53-bit mantissa/significand)
|
return (guf_rand_u64(state) >> 11u) * 0x1.0p-53; // 11 == 64 - 53 (double has a 53-bit mantissa/significand)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS float guf_rand64_f32(guf_rand64_state *state)
|
GUF_RAND_KWRDS float guf_rand64_f32(guf_rand64_state *state)
|
||||||
{
|
{
|
||||||
return (guf_rand64_u64(state) >> 40u) * 0x1.0p-24f; // 40 == 64 - 24; (float has a 24-bit mantissa/significand)
|
return (guf_rand64_u64(state) >> 40u) * 0x1.0p-24f; // 40 == 64 - 24; (float has a 24-bit mantissa/significand)
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS float guf_rand32_f32(guf_rand32_state *state)
|
GUF_RAND_KWRDS float guf_rand32_f32(guf_rand32_state *state)
|
||||||
{
|
{
|
||||||
@ -512,13 +486,12 @@ GUF_RAND_KWRDS bool guf_rand32_bernoulli_trial_f32(guf_rand32_state *state, floa
|
|||||||
p = guf_clamp_f32(p, 0, 1);
|
p = guf_clamp_f32(p, 0, 1);
|
||||||
return guf_rand32_f32(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
return guf_rand32_f32(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
||||||
}
|
}
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f32(guf_rand64_state *state, float p)
|
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f32(guf_rand64_state *state, float p)
|
||||||
{
|
{
|
||||||
p = guf_clamp_f32(p, 0, 1);
|
p = guf_clamp_f32(p, 0, 1);
|
||||||
return guf_rand64_f32(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
return guf_rand64_f32(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p)
|
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f32(guf_randstate *state, float p)
|
||||||
{
|
{
|
||||||
@ -532,13 +505,11 @@ GUF_RAND_KWRDS bool guf_rand32_bernoulli_trial_f64(guf_rand32_state *state, doub
|
|||||||
return guf_rand32_f64(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
return guf_rand32_f64(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f64(guf_rand64_state *state, double p)
|
GUF_RAND_KWRDS bool guf_rand64_bernoulli_trial_f64(guf_rand64_state *state, double p)
|
||||||
{
|
{
|
||||||
p = guf_clamp_f64(p, 0, 1);
|
p = guf_clamp_f64(p, 0, 1);
|
||||||
return guf_rand64_f64(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
return guf_rand64_f64(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p)
|
GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p)
|
||||||
{
|
{
|
||||||
@ -546,17 +517,16 @@ GUF_RAND_KWRDS bool guf_rand_bernoulli_trial_f64(guf_randstate *state, double p)
|
|||||||
return guf_rand_f64(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
return guf_rand_f64(state) < p; // never true for p = 0, always true for p = 1 since guf_rand_f64 is in range [0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS bool guf_rand32_flip(guf_rand32_state *state)
|
GUF_RAND_KWRDS bool guf_rand32_flip(guf_rand32_state *state)
|
||||||
{
|
{
|
||||||
return guf_rand32_bernoulli_trial_f32(state, 0.5f);
|
return guf_rand32_bernoulli_trial_f32(state, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS bool guf_rand64_flip(guf_rand64_state *state)
|
GUF_RAND_KWRDS bool guf_rand64_flip(guf_rand64_state *state)
|
||||||
{
|
{
|
||||||
return guf_rand64_bernoulli_trial_f64(state, 0.5);
|
return guf_rand64_bernoulli_trial_f64(state, 0.5);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS bool guf_rand_flip(guf_randstate *state)
|
GUF_RAND_KWRDS bool guf_rand_flip(guf_randstate *state)
|
||||||
{
|
{
|
||||||
@ -567,6 +537,7 @@ GUF_RAND_KWRDS bool guf_rand_flip(guf_randstate *state)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS double guf_rand32_range_f64(guf_rand32_state *state, double min, double end)
|
GUF_RAND_KWRDS double guf_rand32_range_f64(guf_rand32_state *state, double min, double end)
|
||||||
{
|
{
|
||||||
if (min == (double)INFINITY) {
|
if (min == (double)INFINITY) {
|
||||||
@ -583,7 +554,6 @@ GUF_RAND_KWRDS double guf_rand32_range_f64(guf_rand32_state *state, double min,
|
|||||||
return guf_rand32_f64(state) * (end - min) + min;
|
return guf_rand32_f64(state) * (end - min) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS double guf_rand64_range_f64(guf_rand64_state *state, double min, double end)
|
GUF_RAND_KWRDS double guf_rand64_range_f64(guf_rand64_state *state, double min, double end)
|
||||||
{
|
{
|
||||||
if (min == (double)INFINITY) {
|
if (min == (double)INFINITY) {
|
||||||
@ -599,7 +569,6 @@ GUF_RAND_KWRDS double guf_rand32_range_f64(guf_rand32_state *state, double min,
|
|||||||
GUF_ASSERT_RELEASE(end >= min);
|
GUF_ASSERT_RELEASE(end >= min);
|
||||||
return guf_rand64_f64(state) * (end - min) + min;
|
return guf_rand64_f64(state) * (end - min) + min;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// returns uniformly-distributed random double in range [min, end) (or min if min == end)
|
// returns uniformly-distributed random double in range [min, end) (or min if min == end)
|
||||||
GUF_RAND_KWRDS double guf_randrange_f64(guf_randstate *state, double min, double end)
|
GUF_RAND_KWRDS double guf_randrange_f64(guf_randstate *state, double min, double end)
|
||||||
@ -611,6 +580,7 @@ GUF_RAND_KWRDS double guf_randrange_f64(guf_randstate *state, double min, double
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns uniformly-distributed random float in range [min, end) (or min if min == end)
|
// returns uniformly-distributed random float in range [min, end) (or min if min == end)
|
||||||
GUF_RAND_KWRDS float guf_rand32_range_f32(guf_rand32_state *state, float min, float end)
|
GUF_RAND_KWRDS float guf_rand32_range_f32(guf_rand32_state *state, float min, float end)
|
||||||
{
|
{
|
||||||
@ -628,7 +598,6 @@ GUF_RAND_KWRDS float guf_rand32_range_f32(guf_rand32_state *state, float min, fl
|
|||||||
return guf_rand32_f32(state) * (end - min) + min;
|
return guf_rand32_f32(state) * (end - min) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
// returns uniformly-distributed random float in range [min, end) (or min if min == end)
|
// returns uniformly-distributed random float in range [min, end) (or min if min == end)
|
||||||
GUF_RAND_KWRDS float guf_rand64_range_f32(guf_rand64_state *state, float min, float end)
|
GUF_RAND_KWRDS float guf_rand64_range_f32(guf_rand64_state *state, float min, float end)
|
||||||
{
|
{
|
||||||
@ -645,7 +614,6 @@ GUF_RAND_KWRDS float guf_rand32_range_f32(guf_rand32_state *state, float min, fl
|
|||||||
GUF_ASSERT_RELEASE(end >= min);
|
GUF_ASSERT_RELEASE(end >= min);
|
||||||
return guf_rand64_f32(state) * (end - min) + min;
|
return guf_rand64_f32(state) * (end - min) + min;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// returns uniformly-distributed random float in range [min, end) (or min if min == end)
|
// returns uniformly-distributed random float in range [min, end) (or min if min == end)
|
||||||
GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float end)
|
GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float end)
|
||||||
@ -658,9 +626,8 @@ GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float en
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
// returns uniformly-distributed random i32 in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
||||||
// returns uniformly-distributed random int32_t in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
GUF_RAND_KWRDS int_fast32_t guf_rand64_range_i32(guf_rand64_state *state, int_fast32_t min, int_fast32_t max)
|
||||||
GUF_RAND_KWRDS int32_t guf_rand64_range_i32(guf_rand64_state *state, int32_t min, int32_t max)
|
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(max >= min);
|
GUF_ASSERT_RELEASE(max >= min);
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
@ -670,23 +637,25 @@ GUF_RAND_KWRDS float guf_randrange_f32(guf_randstate *state, float min, float en
|
|||||||
// cf. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random (last-retrieved 2025-02-12)
|
// cf. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random (last-retrieved 2025-02-12)
|
||||||
const double result = floor(guf_rand64_f64(state) * (delta + 1.0) + min);
|
const double result = floor(guf_rand64_f64(state) * (delta + 1.0) + min);
|
||||||
GUF_ASSERT(result >= min && result <= max);
|
GUF_ASSERT(result >= min && result <= max);
|
||||||
return (int32_t)result;
|
#ifdef INT32_MAX
|
||||||
}
|
GUF_ASSERT((int_fast32_t)result <= INT32_MAX && (int_fast32_t)result >= INT32_MIN);
|
||||||
#endif
|
#endif
|
||||||
|
return (int_fast32_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
// returns uniformly-distributed random int32_t in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
// returns uniformly-distributed random i32 in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
||||||
GUF_RAND_KWRDS int32_t guf_rand32_range_i32(guf_rand32_state *state, int32_t min, int32_t max)
|
GUF_RAND_KWRDS int_fast32_t guf_rand32_range_i32(guf_rand32_state *state, int_fast32_t min, int_fast32_t max)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(max >= min);
|
GUF_ASSERT_RELEASE(max >= min);
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t rand_max_i32 = UINT32_MAX >> 1u; // 2^31 - 1 (== INT32_MAX)
|
const uint_fast32_t rand_max_i32 = GUF_UWRAP_32(GUF_UINT32_MAX >> 1u); // 2^31 - 1 (== INT32_MAX)
|
||||||
|
|
||||||
const uint32_t delta = guf_absdiff_i32(max, min);
|
const uint_fast32_t delta = guf_absdiff_int_fast32_t(max, min);
|
||||||
if (delta > rand_max_i32) {
|
if (delta > rand_max_i32) {
|
||||||
guf_panic(GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in function guf_rand32_range_i32: interval [min, max] larger than INT32_MAX"));
|
guf_panic(GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in function guf_rand32_range_i32: interval [min, max] larger than 2^31 - 1"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -696,32 +665,36 @@ GUF_RAND_KWRDS int32_t guf_rand32_range_i32(guf_rand32_state *state, int32_t min
|
|||||||
cf. https://c-faq.com/lib/randrange.html (last-retrieved 2025-02-11)
|
cf. https://c-faq.com/lib/randrange.html (last-retrieved 2025-02-11)
|
||||||
https://stackoverflow.com/a/6852396 (last-retrieved 2025-02-11)
|
https://stackoverflow.com/a/6852396 (last-retrieved 2025-02-11)
|
||||||
*/
|
*/
|
||||||
const uint32_t num_rand_vals = rand_max_i32 + 1u; // 2^31
|
const uint_fast32_t num_rand_vals = GUF_UWRAP_32(rand_max_i32 + 1u); // 2^31
|
||||||
const uint32_t num_bins = (delta + 1u);
|
const uint_fast32_t num_bins = GUF_UWRAP_32(delta + 1u);
|
||||||
|
|
||||||
const uint32_t bin_size = num_rand_vals / num_bins; // bin_size = floor(num_rand_vals / num_bins)
|
const uint_fast32_t bin_size = GUF_UWRAP_32(num_rand_vals / num_bins); // bin_size = floor(num_rand_vals / num_bins)
|
||||||
const uint32_t limit = num_rand_vals - (num_rand_vals % num_bins); // limit == bin_size * num_bins
|
const uint_fast32_t limit = GUF_UWRAP_32(num_rand_vals - (num_rand_vals % num_bins)); // limit == bin_size * num_bins
|
||||||
GUF_ASSERT(limit == bin_size * num_bins);
|
GUF_ASSERT(limit == 1u * GUF_UWRAP_32(bin_size * num_bins));
|
||||||
/*
|
/*
|
||||||
since (num_rand_vals % num_bins) is at most 2^30 + 1 (I think...), the minimum limit is 2^31 - (2^30 + 1),
|
since (num_rand_vals % num_bins) is at most 2^30 + 1 (I think...), the minimum limit is 2^31 - (2^30 + 1),
|
||||||
which means in the worst case, the chance of having to iterate (i.e. step >= limit)
|
which means in the worst case, the chance of having to iterate (i.e. step >= limit)
|
||||||
is 1 - (2^31 - (2^30 + 1)) / 2^31 == 0.5
|
is 1 - (2^31 - (2^30 + 1)) / 2^31 == 0.5
|
||||||
*/
|
*/
|
||||||
uint32_t step;
|
uint_fast32_t step;
|
||||||
do {
|
do {
|
||||||
step = guf_rand32_u32(state) >> 1u; // [0, 2^31 - 1]
|
step = GUF_UWRAP_32(guf_rand32_u32(state) >> 1u); // [0, 2^31 - 1]
|
||||||
} while (step >= limit);
|
} while (step >= limit);
|
||||||
step = step / bin_size;
|
step = GUF_UWRAP_32(step / bin_size);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef INT32_MAX
|
||||||
GUF_ASSERT(guf_ckd_add_i32(min, step) == GUF_MATH_CKD_SUCCESS);
|
GUF_ASSERT(guf_ckd_add_i32(min, step) == GUF_MATH_CKD_SUCCESS);
|
||||||
const int32_t rnd = min + (int32_t)step;
|
#endif
|
||||||
|
const int_fast32_t rnd = min + (int_fast32_t)step;
|
||||||
GUF_ASSERT(rnd >= min && rnd <= max);
|
GUF_ASSERT(rnd >= min && rnd <= max);
|
||||||
|
#ifdef INT32_MAX
|
||||||
|
GUF_ASSERT(rnd <= INT32_MAX && rnd >= INT32_MIN);
|
||||||
|
#endif
|
||||||
return rnd;
|
return rnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns uniformly-distributed random int32_t in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
// returns uniformly-distributed random i32 in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
||||||
GUF_RAND_KWRDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int32_t max)
|
GUF_RAND_KWRDS int_fast32_t guf_randrange_i32(guf_randstate *state, int_fast32_t min, int_fast32_t max)
|
||||||
{
|
{
|
||||||
#ifdef GUF_RAND_32_BIT
|
#ifdef GUF_RAND_32_BIT
|
||||||
return guf_rand32_range_i32(state, min, max);
|
return guf_rand32_range_i32(state, min, max);
|
||||||
@ -730,38 +703,45 @@ GUF_RAND_KWRDS int32_t guf_randrange_i32(guf_randstate *state, int32_t min, int3
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand32_range_u32(guf_rand32_state *state, uint32_t min, uint32_t max)
|
GUF_RAND_KWRDS uint_fast32_t guf_rand32_range_u32(guf_rand32_state *state, uint_fast32_t min, uint_fast32_t max)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
The method used in guf_rand32_range_i32 above (which uses only 32-bit integer arithmetic) could overflow here,
|
The method used in guf_rand32_range_i32 above (which uses only 32-bit integer arithmetic) could overflow here,
|
||||||
so we use the floating-point method since we have to use 64-bit arithmetic anyways.
|
so we use the floating-point method since we have to use 64-bit arithmetic anyways.
|
||||||
*/
|
*/
|
||||||
|
min = GUF_UWRAP_32(min);
|
||||||
|
max = GUF_UWRAP_32(max);
|
||||||
|
|
||||||
GUF_ASSERT_RELEASE(max >= min);
|
GUF_ASSERT_RELEASE(max >= min);
|
||||||
|
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
const double delta = (double)max - (double)min;
|
const double delta = (double)max - (double)min;
|
||||||
const double result = floor(guf_rand32_f64(state) * (delta + 1.0) + min); // NOTE: guf_rand32_f64 is slow for 32-bit platforms...
|
const double result = floor(guf_rand32_f64(state) * (delta + 1.0) + min); // NOTE: guf_rand32_f64 is slow for 32-bit platforms...
|
||||||
GUF_ASSERT(result >= min && result <= max);
|
GUF_ASSERT(result >= min && result <= max);
|
||||||
return (uint32_t)result;
|
GUF_ASSERT((uint_fast32_t)result <= GUF_UINT32_MAX);
|
||||||
|
return (uint_fast32_t)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS uint_fast32_t guf_rand64_range_u32(guf_rand64_state *state, uint_fast32_t min, uint_fast32_t max)
|
||||||
GUF_RAND_KWRDS uint32_t guf_rand64_range_u32(guf_rand64_state *state, uint32_t min, uint32_t max)
|
|
||||||
{
|
{
|
||||||
|
min = GUF_UWRAP_32(min);
|
||||||
|
max = GUF_UWRAP_32(max);
|
||||||
|
|
||||||
GUF_ASSERT_RELEASE(max >= min);
|
GUF_ASSERT_RELEASE(max >= min);
|
||||||
|
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
const double delta = (double)max - (double)min;
|
const double delta = (double)max - (double)min;
|
||||||
const double result = floor(guf_rand64_f64(state) * (delta + 1.0) + min);
|
const double result = floor(guf_rand64_f64(state) * (delta + 1.0) + min);
|
||||||
GUF_ASSERT(result >= min && result <= max);
|
GUF_ASSERT(result >= min && result <= max);
|
||||||
return (uint32_t)result;
|
GUF_ASSERT((uint_fast32_t)result <= GUF_UINT32_MAX);
|
||||||
|
return (uint_fast32_t)result;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, uint32_t max)
|
GUF_RAND_KWRDS uint_fast32_t guf_randrange_u32(guf_randstate *state, uint_fast32_t min, uint_fast32_t max)
|
||||||
{
|
{
|
||||||
#ifdef GUF_RAND_32_BIT
|
#ifdef GUF_RAND_32_BIT
|
||||||
return guf_rand32_range_u32(state, min, max);
|
return guf_rand32_range_u32(state, min, max);
|
||||||
@ -770,19 +750,18 @@ GUF_RAND_KWRDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, ui
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
GUF_RAND_KWRDS int_fast64_t guf_rand64_range_i64(guf_rand64_state *state, int_fast64_t min, int_fast64_t max)
|
||||||
GUF_RAND_KWRDS int64_t guf_rand64_range_i64(guf_rand64_state *state, int64_t min, int64_t max)
|
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(max >= min);
|
GUF_ASSERT_RELEASE(max >= min);
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t rand_max_i64 = UINT64_MAX >> 1u; // 2^63 - 1 (== INT64_MAX)
|
const uint_fast64_t rand_max_i64 = GUF_UWRAP_64(GUF_UINT64_MAX >> 1u); // 2^63 - 1 (== INT64_MAX)
|
||||||
|
|
||||||
const uint64_t delta = guf_absdiff_i64(max, min);
|
const uint_fast64_t delta = guf_absdiff_int_fast64_t(max, min);
|
||||||
if (delta > rand_max_i64) {
|
if (delta > rand_max_i64) {
|
||||||
guf_panic(GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in function guf_randrange_i64: interval [min, max] larger than INT64_MAX"));
|
guf_panic(GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in function guf_randrange_i64: interval [min, max] larger than 2^63 - 1"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -791,37 +770,86 @@ GUF_RAND_KWRDS uint32_t guf_randrange_u32(guf_randstate *state, uint32_t min, ui
|
|||||||
cf. https://c-faq.com/lib/randrange.html (last-retrieved 2025-02-11)
|
cf. https://c-faq.com/lib/randrange.html (last-retrieved 2025-02-11)
|
||||||
https://stackoverflow.com/a/6852396 (last-retrieved 2025-02-11)
|
https://stackoverflow.com/a/6852396 (last-retrieved 2025-02-11)
|
||||||
*/
|
*/
|
||||||
const uint64_t num_rand_vals = rand_max_i64 + 1u; // 2^63
|
const uint_fast64_t num_rand_vals = GUF_UWRAP_64(rand_max_i64 + 1u); // 2^63
|
||||||
const uint64_t num_bins = (delta + 1u);
|
const uint_fast64_t num_bins = GUF_UWRAP_64(delta + 1u);
|
||||||
|
|
||||||
const uint64_t bin_size = num_rand_vals / num_bins; // bin_size = floor(num_rand_vals / num_bins)
|
const uint_fast64_t bin_size = GUF_UWRAP_64(num_rand_vals / num_bins); // bin_size = floor(num_rand_vals / num_bins)
|
||||||
const uint64_t limit = num_rand_vals - (num_rand_vals % num_bins); // limit == bin_size * num_bins
|
const uint_fast64_t limit = GUF_UWRAP_64(num_rand_vals - (num_rand_vals % num_bins)); // limit == bin_size * num_bins
|
||||||
GUF_ASSERT(limit == bin_size * num_bins);
|
GUF_ASSERT(limit == 1u * GUF_UWRAP_64(bin_size * num_bins));
|
||||||
/*
|
/*
|
||||||
since (num_rand_vals % num_bins) is at most 2^62 + 1 (I think...), the minimum limit is 2^63 - (2^62 + 1),
|
since (num_rand_vals % num_bins) is at most 2^62 + 1 (I think...), the minimum limit is 2^63 - (2^62 + 1),
|
||||||
which means in the worst case, the chance of having to iterate (i.e. step >= limit)
|
which means in the worst case, the chance of having to iterate (i.e. step >= limit)
|
||||||
is 1 - (2^63 - (2^62 + 1)) / 2^63 == 0.5
|
is 1 - (2^63 - (2^62 + 1)) / 2^63 == 0.5
|
||||||
*/
|
*/
|
||||||
uint64_t step;
|
uint_fast64_t step;
|
||||||
do {
|
do {
|
||||||
step = guf_rand64_u64(state) >> 1; // [0, 2^63 - 1]
|
step = GUF_UWRAP_64(guf_rand64_u64(state) >> 1); // [0, 2^63 - 1]
|
||||||
} while (step >= limit);
|
} while (step >= limit);
|
||||||
step = step / bin_size;
|
step = GUF_UWRAP_64(step / bin_size);
|
||||||
|
|
||||||
|
#ifdef INT64_MAX
|
||||||
GUF_ASSERT(guf_ckd_add_i64(min, step) == GUF_MATH_CKD_SUCCESS);
|
GUF_ASSERT(guf_ckd_add_i64(min, step) == GUF_MATH_CKD_SUCCESS);
|
||||||
const int64_t rnd = min + (int64_t)step;
|
#endif
|
||||||
|
const int_fast64_t rnd = min + (int_fast64_t)step;
|
||||||
GUF_ASSERT(rnd >= min && rnd <= max);
|
GUF_ASSERT(rnd >= min && rnd <= max);
|
||||||
return rnd;
|
return rnd;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GUF_RAND_32_BIT) && defined(UINT64_MAX)
|
GUF_RAND_KWRDS int_fast64_t guf_rand32_range_i64(guf_rand32_state *state, int_fast64_t min, int_fast64_t max)
|
||||||
// returns uniformly-distributed random int64_t in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
|
||||||
GUF_RAND_KWRDS int64_t guf_randrange_i64(guf_randstate *state, int64_t min, int64_t max)
|
|
||||||
{
|
{
|
||||||
return guf_rand64_range_i64(state, min, max);
|
GUF_ASSERT_RELEASE(max >= min);
|
||||||
|
if (min == max) {
|
||||||
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint_fast64_t rand_max_i64 = GUF_UWRAP_64(GUF_UINT64_MAX >> 1u); // 2^63 - 1 (== INT64_MAX)
|
||||||
|
|
||||||
|
const uint_fast64_t delta = guf_absdiff_int_fast64_t(max, min);
|
||||||
|
if (delta > rand_max_i64) {
|
||||||
|
guf_panic(GUF_ERR_INT_OVERFLOW, GUF_ERR_MSG("in function guf_randrange_i64: interval [min, max] larger than 2^63 - 1"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
We should not use the same approach as in guf_rand64_range_i32 because (max - min) might be close to 2^63 - 1
|
||||||
|
|
||||||
|
cf. https://c-faq.com/lib/randrange.html (last-retrieved 2025-02-11)
|
||||||
|
https://stackoverflow.com/a/6852396 (last-retrieved 2025-02-11)
|
||||||
|
*/
|
||||||
|
const uint_fast64_t num_rand_vals = GUF_UWRAP_64(rand_max_i64 + 1u); // 2^63
|
||||||
|
const uint_fast64_t num_bins = GUF_UWRAP_64(delta + 1u);
|
||||||
|
|
||||||
|
const uint_fast64_t bin_size = GUF_UWRAP_64(num_rand_vals / num_bins); // bin_size = floor(num_rand_vals / num_bins)
|
||||||
|
const uint_fast64_t limit = GUF_UWRAP_64(num_rand_vals - (num_rand_vals % num_bins)); // limit == bin_size * num_bins
|
||||||
|
GUF_ASSERT(limit == 1u * GUF_UWRAP_64(bin_size * num_bins));
|
||||||
|
/*
|
||||||
|
since (num_rand_vals % num_bins) is at most 2^62 + 1 (I think...), the minimum limit is 2^63 - (2^62 + 1),
|
||||||
|
which means in the worst case, the chance of having to iterate (i.e. step >= limit)
|
||||||
|
is 1 - (2^63 - (2^62 + 1)) / 2^63 == 0.5
|
||||||
|
*/
|
||||||
|
uint_fast64_t step;
|
||||||
|
do {
|
||||||
|
step = GUF_UWRAP_64(guf_rand32_u64(state) >> 1); // [0, 2^63 - 1]
|
||||||
|
} while (step >= limit);
|
||||||
|
step = GUF_UWRAP_64(step / bin_size);
|
||||||
|
|
||||||
|
#ifdef INT64_MAX
|
||||||
|
GUF_ASSERT(guf_ckd_add_i64(min, step) == GUF_MATH_CKD_SUCCESS);
|
||||||
#endif
|
#endif
|
||||||
|
const int_fast64_t rnd = min + (int_fast64_t)step;
|
||||||
|
GUF_ASSERT(rnd >= min && rnd <= max);
|
||||||
|
return rnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns uniformly-distributed random int64_t in range [min, max] (max is inclusive as opposed to the f32/f64 versions)
|
||||||
|
GUF_RAND_KWRDS int_fast64_t guf_randrange_i64(guf_randstate *state, int_fast64_t min, int_fast64_t max)
|
||||||
|
{
|
||||||
|
#ifdef GUF_RAND_32_BIT
|
||||||
|
return guf_rand32_range_i64(state, min, max);
|
||||||
|
#else
|
||||||
|
return guf_rand64_range_i64(state, min, max);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Box-Müller-transform transcribed from wikipedia, cf. https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform (last-retrieved 2025-02-12)
|
// Box-Müller-transform transcribed from wikipedia, cf. https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform (last-retrieved 2025-02-12)
|
||||||
GUF_RAND_KWRDS void guf_rand32_normal_sample_f64(guf_rand32_state *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
GUF_RAND_KWRDS void guf_rand32_normal_sample_f64(guf_rand32_state *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
||||||
@ -846,7 +874,6 @@ GUF_RAND_KWRDS void guf_rand32_normal_sample_f64(guf_rand32_state *state, double
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
// Box-Müller-transform transcribed from wikipedia, cf. https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform (last-retrieved 2025-02-12)
|
// Box-Müller-transform transcribed from wikipedia, cf. https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform (last-retrieved 2025-02-12)
|
||||||
GUF_RAND_KWRDS void guf_rand64_normal_sample_f64(guf_rand64_state *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
GUF_RAND_KWRDS void guf_rand64_normal_sample_f64(guf_rand64_state *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
||||||
{
|
{
|
||||||
@ -869,7 +896,6 @@ GUF_RAND_KWRDS void guf_rand32_normal_sample_f64(guf_rand32_state *state, double
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Box-Müller-transform transcribed from wikipedia, cf. https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform (last-retrieved 2025-02-12)
|
// Box-Müller-transform transcribed from wikipedia, cf. https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform (last-retrieved 2025-02-12)
|
||||||
GUF_RAND_KWRDS void guf_rand_normal_sample_f64(guf_randstate *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
GUF_RAND_KWRDS void guf_rand_normal_sample_f64(guf_randstate *state, double mean, double std_dev, double *result, ptrdiff_t n)
|
||||||
@ -903,7 +929,6 @@ GUF_RAND_KWRDS void guf_rand32_normal_sample_f32(guf_rand32_state *state, float
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS void guf_rand64_normal_sample_f32(guf_rand64_state *state, float mean, float std_dev, float *result, ptrdiff_t n)
|
GUF_RAND_KWRDS void guf_rand64_normal_sample_f32(guf_rand64_state *state, float mean, float std_dev, float *result, ptrdiff_t n)
|
||||||
{
|
{
|
||||||
GUF_ASSERT_RELEASE(result);
|
GUF_ASSERT_RELEASE(result);
|
||||||
@ -925,7 +950,6 @@ GUF_RAND_KWRDS void guf_rand32_normal_sample_f32(guf_rand32_state *state, float
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n)
|
GUF_RAND_KWRDS void guf_rand_normal_sample_f32(guf_randstate *state, float mean, float std_dev, float *result, ptrdiff_t n)
|
||||||
{
|
{
|
||||||
@ -943,14 +967,12 @@ GUF_RAND_KWRDS double guf_rand32_normal_sample_one_f64(guf_rand32_state *state,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS double guf_rand64_normal_sample_one_f64(guf_rand64_state *state, double mean, double std_dev)
|
GUF_RAND_KWRDS double guf_rand64_normal_sample_one_f64(guf_rand64_state *state, double mean, double std_dev)
|
||||||
{
|
{
|
||||||
double result;
|
double result;
|
||||||
guf_rand64_normal_sample_f64(state, mean, std_dev, &result, 1);
|
guf_rand64_normal_sample_f64(state, mean, std_dev, &result, 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev)
|
GUF_RAND_KWRDS double guf_rand_normal_sample_one_f64(guf_randstate *state, double mean, double std_dev)
|
||||||
{
|
{
|
||||||
@ -968,14 +990,12 @@ GUF_RAND_KWRDS float guf_rand32_normal_sample_one_f32(guf_rand32_state *state, f
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UINT64_MAX
|
|
||||||
GUF_RAND_KWRDS float guf_rand64_normal_sample_one_f32(guf_rand64_state *state, float mean, float std_dev)
|
GUF_RAND_KWRDS float guf_rand64_normal_sample_one_f32(guf_rand64_state *state, float mean, float std_dev)
|
||||||
{
|
{
|
||||||
float result;
|
float result;
|
||||||
guf_rand64_normal_sample_f32(state, mean, std_dev, &result, 1);
|
guf_rand64_normal_sample_f32(state, mean, std_dev, &result, 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
GUF_RAND_KWRDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev)
|
GUF_RAND_KWRDS float guf_rand_normal_sample_one_f32(guf_randstate *state, float mean, float std_dev)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -94,8 +94,8 @@ GUF_STR_KWRDS int guf_str_view_cmp(const void *str_view_a, const void *str_view_
|
|||||||
|
|
||||||
// Hash functions.
|
// Hash functions.
|
||||||
GUF_STR_KWRDS guf_hash_size_t guf_str_view_hash(const guf_str_view *sv);
|
GUF_STR_KWRDS guf_hash_size_t guf_str_view_hash(const guf_str_view *sv);
|
||||||
GUF_STR_KWRDS uint64_t guf_str_view_hash64(const guf_str_view *sv);
|
GUF_STR_KWRDS uint_fast64_t guf_str_view_hash64(const guf_str_view *sv);
|
||||||
GUF_STR_KWRDS uint32_t guf_str_view_hash32(const guf_str_view *sv);
|
GUF_STR_KWRDS uint_fast32_t guf_str_view_hash32(const guf_str_view *sv);
|
||||||
|
|
||||||
// Return a new guf_str_view corresponding to the substring with leading/trailing ascii-whitespace chars removed from the left/right
|
// Return a new guf_str_view corresponding to the substring with leading/trailing ascii-whitespace chars removed from the left/right
|
||||||
GUF_STR_KWRDS guf_str_view guf_str_view_trim_left_ascii(guf_str_view sv);
|
GUF_STR_KWRDS guf_str_view guf_str_view_trim_left_ascii(guf_str_view sv);
|
||||||
@ -151,8 +151,8 @@ GUF_STR_KWRDS int guf_str_cmp(const guf_str *a, const guf_str *b);
|
|||||||
|
|
||||||
// Hash-functions.
|
// Hash-functions.
|
||||||
GUF_STR_KWRDS guf_hash_size_t guf_str_hash(const guf_str *str);
|
GUF_STR_KWRDS guf_hash_size_t guf_str_hash(const guf_str *str);
|
||||||
GUF_STR_KWRDS uint64_t guf_str_hash64(const guf_str *str);
|
GUF_STR_KWRDS uint_fast64_t guf_str_hash64(const guf_str *str);
|
||||||
GUF_STR_KWRDS uint32_t guf_str_hash32(const guf_str *str);
|
GUF_STR_KWRDS uint_fast32_t guf_str_hash32(const guf_str *str);
|
||||||
|
|
||||||
// Reserve at least min_capacity characters (excluding the null-terminator) (try to double the current capacity first; if that's not at least min_capacity, set the new capacity to min_capacity instead).
|
// Reserve at least min_capacity characters (excluding the null-terminator) (try to double the current capacity first; if that's not at least min_capacity, set the new capacity to min_capacity instead).
|
||||||
GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t min_capacity, guf_err *err);
|
GUF_STR_KWRDS guf_str *guf_str_try_reserve(guf_str *str, ptrdiff_t min_capacity, guf_err *err);
|
||||||
@ -1196,13 +1196,13 @@ GUF_STR_KWRDS guf_hash_size_t guf_str_hash(const guf_str *str)
|
|||||||
return guf_str_view_hash(&(guf_str_view){.str = guf_str_const_cstr(str), .len = guf_str_len(str)});
|
return guf_str_view_hash(&(guf_str_view){.str = guf_str_const_cstr(str), .len = guf_str_len(str)});
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_STR_KWRDS uint64_t guf_str_hash64(const guf_str *str)
|
GUF_STR_KWRDS uint_fast64_t guf_str_hash64(const guf_str *str)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(guf_str_is_valid(str));
|
GUF_ASSERT(guf_str_is_valid(str));
|
||||||
return guf_str_view_hash64(&(guf_str_view){.str = guf_str_const_cstr(str), .len = guf_str_len(str)});
|
return guf_str_view_hash64(&(guf_str_view){.str = guf_str_const_cstr(str), .len = guf_str_len(str)});
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_STR_KWRDS uint32_t guf_str_hash32(const guf_str *str)
|
GUF_STR_KWRDS uint_fast32_t guf_str_hash32(const guf_str *str)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(guf_str_is_valid(str));
|
GUF_ASSERT(guf_str_is_valid(str));
|
||||||
return guf_str_view_hash32(&(guf_str_view){.str = guf_str_const_cstr(str), .len = guf_str_len(str)});
|
return guf_str_view_hash32(&(guf_str_view){.str = guf_str_const_cstr(str), .len = guf_str_len(str)});
|
||||||
@ -1457,7 +1457,7 @@ GUF_STR_KWRDS guf_hash_size_t guf_str_view_hash(const guf_str_view *sv)
|
|||||||
return guf_hash(sv->str, sv->len, GUF_HASH_INIT);
|
return guf_hash(sv->str, sv->len, GUF_HASH_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_STR_KWRDS uint64_t guf_str_view_hash64(const guf_str_view *sv)
|
GUF_STR_KWRDS uint_fast64_t guf_str_view_hash64(const guf_str_view *sv)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(sv);
|
GUF_ASSERT(sv);
|
||||||
if (!sv->str || sv->len <= 0) {
|
if (!sv->str || sv->len <= 0) {
|
||||||
@ -1466,7 +1466,7 @@ GUF_STR_KWRDS uint64_t guf_str_view_hash64(const guf_str_view *sv)
|
|||||||
return guf_hash64(sv->str, sv->len, GUF_HASH64_INIT);
|
return guf_hash64(sv->str, sv->len, GUF_HASH64_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_STR_KWRDS uint32_t guf_str_view_hash32(const guf_str_view *sv)
|
GUF_STR_KWRDS uint_fast32_t guf_str_view_hash32(const guf_str_view *sv)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(sv);
|
GUF_ASSERT(sv);
|
||||||
if (!sv->str || sv->len <= 0) {
|
if (!sv->str || sv->len <= 0) {
|
||||||
|
|||||||
@ -35,9 +35,9 @@ GUF_UTF8_KWRDS int guf_utf8_char_num_bytes(const guf_utf8_char *c);
|
|||||||
GUF_UTF8_KWRDS bool guf_utf8_char_is_valid(const guf_utf8_char *c);
|
GUF_UTF8_KWRDS bool guf_utf8_char_is_valid(const guf_utf8_char *c);
|
||||||
GUF_UTF8_KWRDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c);
|
GUF_UTF8_KWRDS bool guf_utf8_char_is_whitespace(const guf_utf8_char *c);
|
||||||
|
|
||||||
GUF_UTF8_KWRDS guf_utf8_char guf_utf8_char_new(uint32_t codepoint); // Returns GUF_UTF8_REPLACEMENT_CHAR for invalid codepoints (and for GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT).
|
GUF_UTF8_KWRDS guf_utf8_char guf_utf8_char_new(uint_fast32_t codepoint); // Returns GUF_UTF8_REPLACEMENT_CHAR for invalid codepoints (and for GUF_UTF8_REPLACEMENT_CHAR_CODEPOINT).
|
||||||
GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint32_t codepoint); // Returns false for invalid codepoints.
|
GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint_fast32_t codepoint); // Returns false for invalid codepoints.
|
||||||
GUF_UTF8_KWRDS int32_t guf_utf8_decode(const guf_utf8_char *utf8); // Returns -1 for invalid utf-8.
|
GUF_UTF8_KWRDS int_fast32_t guf_utf8_decode(const guf_utf8_char *utf8); // Returns -1 for invalid utf-8.
|
||||||
|
|
||||||
GUF_UTF8_KWRDS bool guf_utf8_equal(const guf_utf8_char *a, const guf_utf8_char *b);
|
GUF_UTF8_KWRDS bool guf_utf8_equal(const guf_utf8_char *a, const guf_utf8_char *b);
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ GUF_UTF8_KWRDS bool guf_utf8_equal(const guf_utf8_char *a, const guf_utf8_char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cf. https://datatracker.ietf.org/doc/html/rfc3629#section-3 (last-retrieved 2025-03-02)
|
// cf. https://datatracker.ietf.org/doc/html/rfc3629#section-3 (last-retrieved 2025-03-02)
|
||||||
GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint32_t cp)
|
GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint_fast32_t cp)
|
||||||
{
|
{
|
||||||
GUF_ASSERT(result);
|
GUF_ASSERT(result);
|
||||||
|
|
||||||
@ -138,8 +138,8 @@ GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint32_t cp)
|
|||||||
int cp_bits = 0;
|
int cp_bits = 0;
|
||||||
for (int byte_n = num_bytes - 1; byte_n >= 0 && cp > 0; --byte_n) {
|
for (int byte_n = num_bytes - 1; byte_n >= 0 && cp > 0; --byte_n) {
|
||||||
const int bits = (byte_n == 0) ? first_byte_bits : tail_byte_bits;
|
const int bits = (byte_n == 0) ? first_byte_bits : tail_byte_bits;
|
||||||
const uint32_t cp_mask = (UINT32_C(1) << bits) - 1;
|
const uint_fast32_t cp_mask = GUF_UWRAP_32( (UINT32_C(1) << bits) - 1 );
|
||||||
result->bytes[byte_n] = (char)((unsigned char)result->bytes[byte_n] | (cp & cp_mask));
|
result->bytes[byte_n] = (char)(1u * (unsigned char)result->bytes[byte_n] | (cp & cp_mask));
|
||||||
cp = cp >> bits;
|
cp = cp >> bits;
|
||||||
cp_bits += bits;
|
cp_bits += bits;
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ GUF_UTF8_KWRDS bool guf_utf8_encode(guf_utf8_char *result, uint32_t cp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUF_UTF8_KWRDS guf_utf8_char guf_utf8_char_new(uint32_t codepoint)
|
GUF_UTF8_KWRDS guf_utf8_char guf_utf8_char_new(uint_fast32_t codepoint)
|
||||||
{
|
{
|
||||||
guf_utf8_char result = GUF_UTF8_REPLACEMENT_CHAR;
|
guf_utf8_char result = GUF_UTF8_REPLACEMENT_CHAR;
|
||||||
guf_utf8_encode(&result, codepoint);
|
guf_utf8_encode(&result, codepoint);
|
||||||
@ -163,7 +163,7 @@ GUF_UTF8_KWRDS guf_utf8_char guf_utf8_char_new(uint32_t codepoint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cf. https://datatracker.ietf.org/doc/html/rfc3629#section-3 (last-retrieved 2025-03-02)
|
// cf. https://datatracker.ietf.org/doc/html/rfc3629#section-3 (last-retrieved 2025-03-02)
|
||||||
GUF_UTF8_KWRDS int32_t guf_utf8_decode(const guf_utf8_char *c)
|
GUF_UTF8_KWRDS int_fast32_t guf_utf8_decode(const guf_utf8_char *c)
|
||||||
{
|
{
|
||||||
if (!guf_utf8_char_is_valid(c)) {
|
if (!guf_utf8_char_is_valid(c)) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -189,12 +189,12 @@ GUF_UTF8_KWRDS int32_t guf_utf8_decode(const guf_utf8_char *c)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cp = 0;
|
uint_fast32_t cp = 0;
|
||||||
int cp_bits = 0;
|
int cp_bits = 0;
|
||||||
for (int byte_n = num_bytes - 1; byte_n >= 0; --byte_n) {
|
for (int byte_n = num_bytes - 1; byte_n >= 0; --byte_n) {
|
||||||
const int bits = (byte_n == 0) ? first_byte_bits : tail_byte_bits;
|
const int bits = (byte_n == 0) ? first_byte_bits : tail_byte_bits;
|
||||||
const uint32_t byte_mask = (UINT32_C(1) << bits) - 1;
|
const uint_fast32_t byte_mask = GUF_UWRAP_32( (UINT32_C(1) << bits) - 1 );
|
||||||
cp |= ((uint32_t)c->bytes[byte_n] & byte_mask) << cp_bits;
|
cp = GUF_UWRAP_32( cp | GUF_UWRAP_32( 1u * ((uint_fast32_t)c->bytes[byte_n] & byte_mask) << cp_bits ) );
|
||||||
cp_bits += bits;
|
cp_bits += bits;
|
||||||
}
|
}
|
||||||
GUF_ASSERT(cp_bits == first_byte_bits + (num_bytes - 1) * tail_byte_bits);
|
GUF_ASSERT(cp_bits == first_byte_bits + (num_bytes - 1) * tail_byte_bits);
|
||||||
@ -204,8 +204,11 @@ GUF_UTF8_KWRDS int32_t guf_utf8_decode(const guf_utf8_char *c)
|
|||||||
if (!valid) {
|
if (!valid) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef INT32_MAX
|
||||||
GUF_ASSERT(cp <= INT32_MAX);
|
GUF_ASSERT(cp <= INT32_MAX);
|
||||||
return (int32_t)cp;
|
#endif
|
||||||
|
GUF_ASSERT(cp <= INT_FAST32_MAX);
|
||||||
|
return (int_fast32_t)cp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@ void CkdIntTest::test_ckd()
|
|||||||
const int32_t add_res = a + b;
|
const int32_t add_res = a + b;
|
||||||
const guf_math_ckd_result ckd_add = guf_ckd_add_i8((int8_t)a, (int8_t)b);
|
const guf_math_ckd_result ckd_add = guf_ckd_add_i8((int8_t)a, (int8_t)b);
|
||||||
TEST_CHECK(ckd_add == guf_ckd_add_i8((int8_t)b, (int8_t)a));
|
TEST_CHECK(ckd_add == guf_ckd_add_i8((int8_t)b, (int8_t)a));
|
||||||
|
TEST_CHECK(ckd_add == guf_ckd_add_int_fast8_t((int_fast8_t)a, (int_fast8_t)b));
|
||||||
if (add_res > INT8_MAX) {
|
if (add_res > INT8_MAX) {
|
||||||
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
|
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
int8_t saturated, saturated2;
|
int8_t saturated, saturated2;
|
||||||
@ -72,6 +73,7 @@ void CkdIntTest::test_ckd()
|
|||||||
|
|
||||||
const int32_t sub_res = a - b;
|
const int32_t sub_res = a - b;
|
||||||
const guf_math_ckd_result ckd_sub = guf_ckd_sub_i8((int8_t)a, (int8_t)b);
|
const guf_math_ckd_result ckd_sub = guf_ckd_sub_i8((int8_t)a, (int8_t)b);
|
||||||
|
TEST_CHECK(ckd_sub == guf_ckd_sub_int_fast8_t((int_fast8_t)a, (int_fast8_t)b));
|
||||||
if (sub_res > INT8_MAX) {
|
if (sub_res > INT8_MAX) {
|
||||||
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_POS);
|
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
int8_t saturated;
|
int8_t saturated;
|
||||||
@ -100,6 +102,7 @@ void CkdIntTest::test_ckd()
|
|||||||
|
|
||||||
const int32_t mul_res = a * b;
|
const int32_t mul_res = a * b;
|
||||||
const guf_math_ckd_result ckd_mul = guf_ckd_mul_i8((int8_t)a, (int8_t)b);
|
const guf_math_ckd_result ckd_mul = guf_ckd_mul_i8((int8_t)a, (int8_t)b);
|
||||||
|
TEST_CHECK(ckd_mul == guf_ckd_mul_int_fast8_t((int_fast8_t)a, (int_fast8_t)b));
|
||||||
TEST_CHECK(ckd_mul == guf_ckd_mul_i8((int8_t)b, (int8_t)a));
|
TEST_CHECK(ckd_mul == guf_ckd_mul_i8((int8_t)b, (int8_t)a));
|
||||||
if (mul_res > INT8_MAX) {
|
if (mul_res > INT8_MAX) {
|
||||||
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
|
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
@ -220,6 +223,57 @@ void CkdIntTest::test_ckd()
|
|||||||
guf_wrapping_mul_i32(4096, -314159265, &mul_i32_res);
|
guf_wrapping_mul_i32(4096, -314159265, &mul_i32_res);
|
||||||
TEST_CHECK(mul_i32_res == 1693839360);
|
TEST_CHECK(mul_i32_res == 1693839360);
|
||||||
|
|
||||||
|
|
||||||
|
int_fast32_t mul_i32fast_res = -12345;
|
||||||
|
TEST_CHECK(guf_wrapping_mul_int_fast32_t(INT32_MAX, 2, &mul_i32fast_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
|
TEST_CHECK(mul_i32fast_res == -2);
|
||||||
|
mul_i32fast_res = -12345;
|
||||||
|
TEST_CHECK(guf_wrapping_mul_int_fast32_t(2, INT32_MAX, &mul_i32fast_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
|
TEST_CHECK(mul_i32fast_res == -2);
|
||||||
|
|
||||||
|
mul_i32fast_res = -12345;
|
||||||
|
TEST_CHECK(guf_wrapping_mul_int_fast32_t(INT32_MAX, -2, &mul_i32fast_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
||||||
|
TEST_CHECK(mul_i32fast_res == 2);
|
||||||
|
mul_i32fast_res = -12345;
|
||||||
|
TEST_CHECK(guf_wrapping_mul_int_fast32_t(-2, INT32_MAX, &mul_i32fast_res) == GUF_MATH_CKD_OVERFLOW_NEG);
|
||||||
|
TEST_CHECK(mul_i32fast_res == 2);
|
||||||
|
|
||||||
|
TEST_CHECK(guf_wrapping_mul_int_fast32_t(42002718, 314159265, &mul_i32fast_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
|
TEST_CHECK(mul_i32fast_res == -972735522);
|
||||||
|
mul_i32fast_res = -12345;
|
||||||
|
TEST_CHECK(guf_wrapping_mul_int_fast32_t(314159265, 42002718, &mul_i32fast_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
|
TEST_CHECK(mul_i32fast_res == -972735522);
|
||||||
|
|
||||||
|
mul_i32fast_res = 12345;
|
||||||
|
guf_wrapping_mul_int_fast32_t(42002718, 314159265, &mul_i32fast_res);
|
||||||
|
TEST_CHECK(mul_i32fast_res == -972735522);
|
||||||
|
|
||||||
|
mul_i32fast_res = 12345;
|
||||||
|
guf_wrapping_mul_int_fast32_t(-42002718, 314159265, &mul_i32fast_res);
|
||||||
|
TEST_CHECK(mul_i32fast_res == 972735522);
|
||||||
|
|
||||||
|
mul_i32fast_res = 12345;
|
||||||
|
guf_wrapping_mul_int_fast32_t(-88888888, 99999999, &mul_i32fast_res);
|
||||||
|
TEST_CHECK(mul_i32fast_res == 1374494264);
|
||||||
|
|
||||||
|
mul_i32fast_res = 12345;
|
||||||
|
guf_wrapping_mul_int_fast32_t(INT32_MIN, -1, &mul_i32fast_res);
|
||||||
|
TEST_CHECK(mul_i32fast_res == INT32_MIN);
|
||||||
|
|
||||||
|
mul_i32fast_res = 12345;
|
||||||
|
guf_wrapping_mul_int_fast32_t(-2147483648, 2147483640, &mul_i32fast_res);
|
||||||
|
TEST_CHECK(mul_i32fast_res == 0);
|
||||||
|
|
||||||
|
mul_i32fast_res = 12345;
|
||||||
|
guf_wrapping_mul_int_fast32_t(-2048, -314159265, &mul_i32fast_res);
|
||||||
|
TEST_CHECK(mul_i32fast_res == -846919680);
|
||||||
|
|
||||||
|
mul_i32fast_res = 12345;
|
||||||
|
guf_wrapping_mul_int_fast32_t(4096, -314159265, &mul_i32fast_res);
|
||||||
|
TEST_CHECK(mul_i32fast_res == 1693839360);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ptrdiff_t ptrdiff_res = -1234;
|
ptrdiff_t ptrdiff_res = -1234;
|
||||||
TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MAX, 1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MAX, 1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
TEST_CHECK(ptrdiff_res == PTRDIFF_MAX);
|
TEST_CHECK(ptrdiff_res == PTRDIFF_MAX);
|
||||||
@ -241,6 +295,7 @@ void CkdIntTest::test_ckd_uint()
|
|||||||
for (int32_t b = 0; b <= UINT8_MAX; ++b) {
|
for (int32_t b = 0; b <= UINT8_MAX; ++b) {
|
||||||
const int32_t add_res = a + b;
|
const int32_t add_res = a + b;
|
||||||
const guf_math_ckd_result ckd_add = guf_ckd_add_u8((uint8_t)a, (uint8_t)b);
|
const guf_math_ckd_result ckd_add = guf_ckd_add_u8((uint8_t)a, (uint8_t)b);
|
||||||
|
GUF_ASSERT(ckd_add == guf_ckd_add_uint_fast8_t((uint_fast8_t)a, (uint_fast8_t)b));
|
||||||
if (add_res > UINT8_MAX) {
|
if (add_res > UINT8_MAX) {
|
||||||
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
|
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
uint8_t saturated;
|
uint8_t saturated;
|
||||||
@ -262,6 +317,7 @@ void CkdIntTest::test_ckd_uint()
|
|||||||
|
|
||||||
const int32_t sub_res = a - b;
|
const int32_t sub_res = a - b;
|
||||||
const guf_math_ckd_result ckd_sub = guf_ckd_sub_u8((uint8_t)a, (uint8_t)b);
|
const guf_math_ckd_result ckd_sub = guf_ckd_sub_u8((uint8_t)a, (uint8_t)b);
|
||||||
|
GUF_ASSERT(ckd_sub == guf_ckd_sub_uint_fast8_t((uint_fast8_t)a, (uint_fast8_t)b));
|
||||||
if (sub_res < 0) {
|
if (sub_res < 0) {
|
||||||
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_NEG);
|
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_NEG);
|
||||||
uint8_t saturated;
|
uint8_t saturated;
|
||||||
@ -282,6 +338,7 @@ void CkdIntTest::test_ckd_uint()
|
|||||||
|
|
||||||
const int32_t mul_res = a * b;
|
const int32_t mul_res = a * b;
|
||||||
const guf_math_ckd_result ckd_mul = guf_ckd_mul_u8((uint8_t)a, (uint8_t)b);
|
const guf_math_ckd_result ckd_mul = guf_ckd_mul_u8((uint8_t)a, (uint8_t)b);
|
||||||
|
GUF_ASSERT(ckd_mul == guf_ckd_mul_uint_fast8_t((uint_fast8_t)a, (uint_fast8_t)b));
|
||||||
if (mul_res > UINT8_MAX) {
|
if (mul_res > UINT8_MAX) {
|
||||||
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
|
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
uint8_t saturated;
|
uint8_t saturated;
|
||||||
|
|||||||
3
todo.txt
3
todo.txt
@ -1,3 +1,6 @@
|
|||||||
|
|
||||||
|
- make guf_utf8_char 4 bytes (non-null terminated)
|
||||||
|
|
||||||
- guf_stack, guf_queue, guf_dqueue, guf_prio_queue (using a heap), guf_ringbuf
|
- guf_stack, guf_queue, guf_dqueue, guf_prio_queue (using a heap), guf_ringbuf
|
||||||
- sort: add cpp #ifdef to remove restrict from declaration
|
- sort: add cpp #ifdef to remove restrict from declaration
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,10 @@ class IntType:
|
|||||||
INT_TYPE_ABBR: str
|
INT_TYPE_ABBR: str
|
||||||
INT_MIN: str
|
INT_MIN: str
|
||||||
INT_MAX: str
|
INT_MAX: str
|
||||||
UINT_TYPE: str = "size_t"
|
UINT_TYPE: str
|
||||||
|
UINT_MAX: str
|
||||||
|
is_optional: bool = False
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class UintType:
|
class UintType:
|
||||||
@ -20,15 +23,17 @@ class UintType:
|
|||||||
INT_TYPE_ABBR: str
|
INT_TYPE_ABBR: str
|
||||||
INT_MIN: str
|
INT_MIN: str
|
||||||
INT_MAX: str
|
INT_MAX: str
|
||||||
|
is_optional: bool = False
|
||||||
|
|
||||||
def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, str]:
|
def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, str]:
|
||||||
|
|
||||||
ckd_add_sub_uint_header = textwrap.dedent("""
|
ckd_add_sub_uint_header = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b);
|
||||||
""")
|
""")
|
||||||
ckd_add_sub_uint = textwrap.dedent("""
|
|
||||||
|
ckd_add_sub_uint = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
|
||||||
{{
|
{{
|
||||||
if (b > 0 && a > {int_max} - b) {{
|
if (b > 0 && a > {int_max} - b) {{
|
||||||
@ -52,13 +57,43 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
ckd_add_sub_uint_FAST = textwrap.dedent("""\
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
|
||||||
|
{{
|
||||||
|
a = GUF_UWRAP_{bits}(a);
|
||||||
|
b = GUF_UWRAP_{bits}(b);
|
||||||
|
if (b > 0 && a > {int_max} - b) {{
|
||||||
|
return GUF_MATH_CKD_OVERFLOW_POS;
|
||||||
|
}} else {{
|
||||||
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b)
|
||||||
|
{{
|
||||||
|
a = GUF_UWRAP_{bits}(a);
|
||||||
|
b = GUF_UWRAP_{bits}(b);
|
||||||
|
if (b > a) {{
|
||||||
|
return GUF_MATH_CKD_OVERFLOW_NEG;
|
||||||
|
}} else {{
|
||||||
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b)
|
||||||
|
{{
|
||||||
|
a = GUF_UWRAP_{bits}(a);
|
||||||
|
b = GUF_UWRAP_{bits}(b);
|
||||||
|
const {type} c = GUF_UWRAP_{bits}( 1u * a * b );
|
||||||
|
return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
ckd_add_sub_int_header = textwrap.dedent("""
|
ckd_add_sub_int_header = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b);
|
||||||
""")
|
""")
|
||||||
ckd_add_sub_int = textwrap.dedent("""
|
|
||||||
|
ckd_add_sub_int = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
|
||||||
{{
|
{{
|
||||||
if (b > 0 && a > {int_max} - b) {{
|
if (b > 0 && a > {int_max} - b) {{
|
||||||
@ -107,7 +142,7 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
saturating_wrapping_int_header = textwrap.dedent("""
|
saturating_wrapping_int_header = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
@ -116,7 +151,8 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
""")
|
""")
|
||||||
saturating_wrapping_int = textwrap.dedent("""
|
|
||||||
|
saturating_wrapping_int = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
{{
|
{{
|
||||||
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
|
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
|
||||||
@ -232,8 +268,9 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
case GUF_MATH_CKD_OVERFLOW_NEG: {{
|
case GUF_MATH_CKD_OVERFLOW_NEG: {{
|
||||||
{uint_type} res = 1u * ({uint_type})a * ({uint_type})b;
|
{uint_type} res = 1u * ({uint_type})a * ({uint_type})b;
|
||||||
if (res > {int_max}) {{ // This is the fix for implementation defined conversion from unsigned to signed.
|
if (res > {int_max}) {{ // This is the fix for implementation defined conversion from unsigned to signed.
|
||||||
const {uint_type} mod = (1u + ({uint_type}){int_max});
|
const {uint_type} mod = ({uint_type}){int_max} + 1u;
|
||||||
res = mod > 0 ? (1u * res % mod) : res;
|
GUF_ASSERT(mod > 0);
|
||||||
|
res = 1u * res % mod;
|
||||||
*result = {int_min} + ({type})res;
|
*result = {int_min} + ({type})res;
|
||||||
}} else {{
|
}} else {{
|
||||||
*result = ({type})res;
|
*result = ({type})res;
|
||||||
@ -248,7 +285,8 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
saturating_wrapping_uint_header = textwrap.dedent("""
|
|
||||||
|
saturating_wrapping_uint_header = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
@ -258,7 +296,7 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
saturating_wrapping_uint = textwrap.dedent("""
|
saturating_wrapping_uint = textwrap.dedent("""\
|
||||||
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
{{
|
{{
|
||||||
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
|
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
|
||||||
@ -340,29 +378,190 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
saturating_wrapping_uint_FAST = textwrap.dedent("""\
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
|
||||||
|
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
|
if (result) {{
|
||||||
|
switch (check) {{
|
||||||
|
case GUF_MATH_CKD_SUCCESS:
|
||||||
|
*result = a + b;
|
||||||
|
break;
|
||||||
|
case GUF_MATH_CKD_OVERFLOW_POS:
|
||||||
|
*result = {int_max};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
|
||||||
|
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_NEG);
|
||||||
|
if (result) {{
|
||||||
|
switch (check) {{
|
||||||
|
case GUF_MATH_CKD_SUCCESS:
|
||||||
|
*result = a - b;
|
||||||
|
break;
|
||||||
|
case GUF_MATH_CKD_OVERFLOW_NEG:
|
||||||
|
*result = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
|
||||||
|
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
|
||||||
|
if (result) {{
|
||||||
|
switch (check) {{
|
||||||
|
case GUF_MATH_CKD_SUCCESS:
|
||||||
|
*result = a * b;
|
||||||
|
break;
|
||||||
|
case GUF_MATH_CKD_OVERFLOW_POS:
|
||||||
|
*result = {int_max};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
|
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
a = GUF_UWRAP_{bits}(a);
|
||||||
|
b = GUF_UWRAP_{bits}(b);
|
||||||
|
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
|
||||||
|
if (result) {{
|
||||||
|
*result = GUF_UWRAP_{bits}( 1u * a + b );
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
a = GUF_UWRAP_{bits}(a);
|
||||||
|
b = GUF_UWRAP_{bits}(b);
|
||||||
|
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
|
||||||
|
if (result) {{
|
||||||
|
*result = GUF_UWRAP_{bits}( 1u * a - b );
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
|
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
a = GUF_UWRAP_{bits}(a);
|
||||||
|
b = GUF_UWRAP_{bits}(b);
|
||||||
|
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
|
||||||
|
if (result) {{
|
||||||
|
*result = GUF_UWRAP_{bits}( 1u * a * b );
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
text_result = "// Signed integer arithmetic checks (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result = "// Signed integer arithmetic checks (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
text_result_header = text_result
|
text_result_header = text_result
|
||||||
for type in int_types:
|
for type in int_types:
|
||||||
text_result += ckd_add_sub_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX)
|
end = "\n"
|
||||||
text_result_header += ckd_add_sub_int_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX)
|
if type.is_optional:
|
||||||
|
text_result += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
text_result_header += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
end = ""
|
||||||
|
|
||||||
|
text_result += ckd_add_sub_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_max = type.UINT_MAX) + end
|
||||||
|
text_result_header += ckd_add_sub_int_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_max = type.UINT_MAX) + end
|
||||||
|
|
||||||
|
if type.is_optional:
|
||||||
|
text_result += "#endif\n\n"
|
||||||
|
text_result_header += "#endif\n\n"
|
||||||
|
|
||||||
|
|
||||||
text_result += "\n// Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) \n"
|
text_result += "\n// Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) \n"
|
||||||
text_result_header += "\n// Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) \n"
|
text_result_header += "\n// Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) \n"
|
||||||
for type in uint_types:
|
for type in uint_types:
|
||||||
text_result += ckd_add_sub_uint.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX)
|
end = "\n"
|
||||||
text_result_header += ckd_add_sub_uint_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX)
|
if type.is_optional:
|
||||||
|
text_result += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
text_result_header += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
end = ""
|
||||||
|
|
||||||
|
if "uint_fast" in type.INT_TYPE:
|
||||||
|
bits = 0
|
||||||
|
if "fast8" in type.INT_TYPE:
|
||||||
|
bits = 8
|
||||||
|
elif "fast16" in type.INT_TYPE:
|
||||||
|
bits = 16
|
||||||
|
elif "fast32" in type.INT_TYPE:
|
||||||
|
bits = 32
|
||||||
|
elif "fast64" in type.INT_TYPE:
|
||||||
|
bits = 64
|
||||||
|
else:
|
||||||
|
assert(False)
|
||||||
|
text_result += ckd_add_sub_uint_FAST.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, bits = str(bits))
|
||||||
|
else:
|
||||||
|
text_result += ckd_add_sub_uint.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
|
||||||
|
text_result_header += ckd_add_sub_uint_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
|
||||||
|
|
||||||
|
if type.is_optional:
|
||||||
|
text_result += "#endif\n\n"
|
||||||
|
text_result_header += "#endif\n\n"
|
||||||
|
|
||||||
|
|
||||||
text_result += "\n\n// Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result += "\n\n// Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
text_result_header += "\n\n// Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result_header += "\n\n// Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
for type in int_types:
|
for type in int_types:
|
||||||
text_result += saturating_wrapping_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_type = type.UINT_TYPE) + "\n"
|
end = "\n"
|
||||||
text_result_header += saturating_wrapping_int_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_type = type.UINT_TYPE) + "\n"
|
if type.is_optional:
|
||||||
|
text_result += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
text_result_header += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
end = ""
|
||||||
|
|
||||||
|
text_result += saturating_wrapping_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_type = type.UINT_TYPE, uint_max = type.UINT_MAX) + end
|
||||||
|
text_result_header += saturating_wrapping_int_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_type = type.UINT_TYPE, uint_max = type.UINT_MAX) + end
|
||||||
|
|
||||||
|
if type.is_optional:
|
||||||
|
text_result += "#endif\n\n"
|
||||||
|
text_result_header += "#endif\n\n"
|
||||||
|
|
||||||
|
|
||||||
text_result += "\n// Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result += "\n// Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
text_result_header += "\n// Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result_header += "\n// Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
for type in uint_types:
|
for type in uint_types:
|
||||||
text_result += saturating_wrapping_uint.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + "\n"
|
end = "\n"
|
||||||
text_result_header += saturating_wrapping_uint_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + "\n"
|
if type.is_optional:
|
||||||
|
text_result += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
text_result_header += f"#ifdef {type.INT_MAX}\n"
|
||||||
|
end = ""
|
||||||
|
|
||||||
|
if "uint_fast" in type.INT_TYPE:
|
||||||
|
bits = 0
|
||||||
|
if "fast8" in type.INT_TYPE:
|
||||||
|
bits = 8
|
||||||
|
elif "fast16" in type.INT_TYPE:
|
||||||
|
bits = 16
|
||||||
|
elif "fast32" in type.INT_TYPE:
|
||||||
|
bits = 32
|
||||||
|
elif "fast64" in type.INT_TYPE:
|
||||||
|
bits = 64
|
||||||
|
else:
|
||||||
|
assert(False)
|
||||||
|
text_result += saturating_wrapping_uint_FAST.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, bits = str(bits)) + end
|
||||||
|
else:
|
||||||
|
text_result += saturating_wrapping_uint.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
|
||||||
|
|
||||||
|
text_result_header += saturating_wrapping_uint_header.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + end
|
||||||
|
|
||||||
|
if type.is_optional:
|
||||||
|
text_result += "#endif\n\n"
|
||||||
|
text_result_header += "#endif\n\n"
|
||||||
|
|
||||||
|
|
||||||
return (text_result_header, text_result)
|
return (text_result_header, text_result)
|
||||||
|
|
||||||
@ -371,28 +570,41 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
int_types = [
|
int_types = [
|
||||||
IntType(INT_TYPE = "int", INT_TYPE_ABBR = "int", INT_MIN = "INT_MIN", INT_MAX = "INT_MAX", UINT_TYPE = "unsigned"),
|
IntType(INT_TYPE = "int", INT_TYPE_ABBR = "int", INT_MIN = "INT_MIN", INT_MAX = "INT_MAX", UINT_TYPE = "unsigned", UINT_MAX = "UINT_MAX"),
|
||||||
IntType(INT_TYPE = "long", INT_TYPE_ABBR = "long", INT_MIN = "LONG_MIN", INT_MAX = "LONG_MAX", UINT_TYPE = "unsigned long"),
|
IntType(INT_TYPE = "long", INT_TYPE_ABBR = "long", INT_MIN = "LONG_MIN", INT_MAX = "LONG_MAX", UINT_TYPE = "unsigned long", UINT_MAX = "ULONG_MAX"),
|
||||||
IntType(INT_TYPE = "long long", INT_TYPE_ABBR = "long_long", INT_MIN = "LLONG_MIN", INT_MAX = "LLONG_MAX", UINT_TYPE = "unsigned long long"),
|
IntType(INT_TYPE = "long long", INT_TYPE_ABBR = "long_long", INT_MIN = "LLONG_MIN", INT_MAX = "LLONG_MAX", UINT_TYPE = "unsigned long long", UINT_MAX = "ULLONG_MAX"),
|
||||||
|
|
||||||
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX", UINT_TYPE = "uint8_t"),
|
# TODO: size_t is not necessarily the unsigned ptrdiff_t equivalent
|
||||||
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX", UINT_TYPE = "uint16_t"),
|
IntType(INT_TYPE = "ptrdiff_t", INT_TYPE_ABBR = "ptrdiff_t", INT_MIN = "PTRDIFF_MIN", INT_MAX = "PTRDIFF_MAX", UINT_TYPE = "size_t", UINT_MAX = "SIZE_MAX"),
|
||||||
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX", UINT_TYPE = "uint32_t"),
|
|
||||||
IntType(INT_TYPE = "int64_t", INT_TYPE_ABBR = "i64", INT_MIN = "INT64_MIN", INT_MAX = "INT64_MAX", UINT_TYPE = "uint64_t"),
|
IntType(INT_TYPE = "int_fast8_t", INT_TYPE_ABBR = "int_fast8_t", INT_MIN = "GUF_INT8_MIN", INT_MAX = "GUF_INT8_MAX", UINT_TYPE = "uint_fast8_t", UINT_MAX = "GUF_UINT8_MAX"),
|
||||||
IntType(INT_TYPE = "ptrdiff_t", INT_TYPE_ABBR = "ptrdiff_t", INT_MIN = "PTRDIFF_MIN", INT_MAX = "PTRDIFF_MAX", UINT_TYPE = "size_t"), # TODO: size_t is not necessarily the unsigned ptrdiff_t equivalent
|
IntType(INT_TYPE = "int_fast16_t", INT_TYPE_ABBR = "int_fast16_t", INT_MIN = "GUF_INT16_MIN", INT_MAX = "GUF_INT16_MAX", UINT_TYPE = "uint_fast16_t", UINT_MAX = "GUF_UINT16_MAX"),
|
||||||
|
IntType(INT_TYPE = "int_fast32_t", INT_TYPE_ABBR = "int_fast32_t", INT_MIN = "GUF_INT32_MIN", INT_MAX = "GUF_INT32_MAX", UINT_TYPE = "uint_fast32_t", UINT_MAX = "GUF_UINT32_MAX"),
|
||||||
|
IntType(INT_TYPE = "int_fast64_t", INT_TYPE_ABBR = "int_fast64_t", INT_MIN = "GUF_INT64_MIN", INT_MAX = "GUF_INT64_MAX", UINT_TYPE = "uint_fast64_t", UINT_MAX = "GUF_UINT64_MAX"),
|
||||||
|
|
||||||
|
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX", UINT_TYPE = "uint8_t", UINT_MAX = "GUF_UINT8_MAX", is_optional = True),
|
||||||
|
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX", UINT_TYPE = "uint16_t", UINT_MAX = "GUF_UINT16_MAX", is_optional = True),
|
||||||
|
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX", UINT_TYPE = "uint32_t", UINT_MAX = "GUF_UINT32_MAX", is_optional = True),
|
||||||
|
IntType(INT_TYPE = "int64_t", INT_TYPE_ABBR = "i64", INT_MIN = "INT64_MIN", INT_MAX = "INT64_MAX", UINT_TYPE = "uint64_t", UINT_MAX = "GUF_UINT64_MAX", is_optional = True),
|
||||||
]
|
]
|
||||||
|
|
||||||
uint_types = [
|
uint_types = [
|
||||||
UintType(INT_TYPE = "unsigned char", INT_TYPE_ABBR = "uchar", INT_MIN = "0", INT_MAX = "UCHAR_MAX"),
|
UintType(INT_TYPE = "unsigned char", INT_TYPE_ABBR = "uchar", INT_MIN = "0", INT_MAX = "UCHAR_MAX"),
|
||||||
UintType(INT_TYPE = "unsigned", INT_TYPE_ABBR = "unsigned", INT_MIN = "0", INT_MAX = "UINT_MAX"),
|
UintType(INT_TYPE = "unsigned", INT_TYPE_ABBR = "unsigned", INT_MIN = "0", INT_MAX = "UINT_MAX"),
|
||||||
UintType(INT_TYPE = "unsigned long", INT_TYPE_ABBR = "ulong", INT_MIN = "ULONG_MIN", INT_MAX = "ULONG_MAX"),
|
UintType(INT_TYPE = "unsigned long", INT_TYPE_ABBR = "ulong", INT_MIN = "0", INT_MAX = "ULONG_MAX"),
|
||||||
UintType(INT_TYPE = "unsigned long long", INT_TYPE_ABBR = "ulong_long", INT_MIN = "ULLONG_MIN", INT_MAX = "ULLONG_MAX"),
|
UintType(INT_TYPE = "unsigned long long", INT_TYPE_ABBR = "ulong_long", INT_MIN = "0", INT_MAX = "ULLONG_MAX"),
|
||||||
|
|
||||||
UintType(INT_TYPE = "uint8_t", INT_TYPE_ABBR = "u8", INT_MIN = "0", INT_MAX = "UINT8_MAX"),
|
|
||||||
UintType(INT_TYPE = "uint16_t", INT_TYPE_ABBR = "u16", INT_MIN = "0", INT_MAX = "UINT16_MAX"),
|
|
||||||
UintType(INT_TYPE = "uint32_t", INT_TYPE_ABBR = "u32", INT_MIN = "0", INT_MAX = "UINT32_MAX"),
|
|
||||||
UintType(INT_TYPE = "uint64_t", INT_TYPE_ABBR = "u64", INT_MIN = "0", INT_MAX = "UINT64_MAX"),
|
|
||||||
UintType(INT_TYPE = "size_t", INT_TYPE_ABBR = "size_t", INT_MIN = "0", INT_MAX = "SIZE_MAX"),
|
UintType(INT_TYPE = "size_t", INT_TYPE_ABBR = "size_t", INT_MIN = "0", INT_MAX = "SIZE_MAX"),
|
||||||
|
|
||||||
|
UintType(INT_TYPE = "uint_fast8_t", INT_TYPE_ABBR = "uint_fast8_t", INT_MIN = "0", INT_MAX = "GUF_UINT8_MAX"),
|
||||||
|
UintType(INT_TYPE = "uint_fast16_t", INT_TYPE_ABBR = "uint_fast16_t", INT_MIN = "0", INT_MAX = "GUF_UINT16_MAX"),
|
||||||
|
UintType(INT_TYPE = "uint_fast32_t", INT_TYPE_ABBR = "uint_fast32_t", INT_MIN = "0", INT_MAX = "GUF_UINT32_MAX"),
|
||||||
|
UintType(INT_TYPE = "uint_fast64_t", INT_TYPE_ABBR = "uint_fast64_t", INT_MIN = "0", INT_MAX = "GUF_UINT64_MAX"),
|
||||||
|
|
||||||
|
UintType(INT_TYPE = "uint8_t", INT_TYPE_ABBR = "u8", INT_MIN = "0", INT_MAX = "UINT8_MAX", is_optional = True),
|
||||||
|
UintType(INT_TYPE = "uint16_t", INT_TYPE_ABBR = "u16", INT_MIN = "0", INT_MAX = "UINT16_MAX", is_optional = True),
|
||||||
|
UintType(INT_TYPE = "uint32_t", INT_TYPE_ABBR = "u32", INT_MIN = "0", INT_MAX = "UINT32_MAX", is_optional = True),
|
||||||
|
UintType(INT_TYPE = "uint64_t", INT_TYPE_ABBR = "u64", INT_MIN = "0", INT_MAX = "UINT64_MAX", is_optional = True),
|
||||||
]
|
]
|
||||||
|
|
||||||
code_header, code_impl = generate_ckdint_functions(int_types = int_types, uint_types= uint_types)
|
code_header, code_impl = generate_ckdint_functions(int_types = int_types, uint_types= uint_types)
|
||||||
|
|||||||
@ -11,6 +11,7 @@ class IntType:
|
|||||||
INT_TYPE_ABBR: str
|
INT_TYPE_ABBR: str
|
||||||
INT_MIN: str
|
INT_MIN: str
|
||||||
INT_MAX: str
|
INT_MAX: str
|
||||||
|
is_optional: bool = False
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class UintType:
|
class UintType:
|
||||||
@ -18,10 +19,11 @@ class UintType:
|
|||||||
INT_TYPE_ABBR: str
|
INT_TYPE_ABBR: str
|
||||||
INT_MIN: str
|
INT_MIN: str
|
||||||
INT_MAX: str
|
INT_MAX: str
|
||||||
|
is_optional: bool = False
|
||||||
|
|
||||||
|
|
||||||
def gen_min_max_clamp(int_types: list, uint_types: list) -> str:
|
def gen_min_max_clamp(int_types: list, uint_types: list) -> str:
|
||||||
template = textwrap.dedent("""
|
template = textwrap.dedent("""\
|
||||||
static inline {type} guf_min_{type_abbr}({type} a, {type} b) {{ return a < b ? a : b; }}
|
static inline {type} guf_min_{type_abbr}({type} a, {type} b) {{ return a < b ? a : b; }}
|
||||||
static inline {type} guf_max_{type_abbr}({type} a, {type} b) {{ return a > b ? a : b; }}
|
static inline {type} guf_max_{type_abbr}({type} a, {type} b) {{ return a > b ? a : b; }}
|
||||||
static inline {type} guf_clamp_{type_abbr}({type} x, {type} min, {type} max) {{ if (x < min) {{return min;}} if (x > max) {{return max;}} return x; }}
|
static inline {type} guf_clamp_{type_abbr}({type} x, {type} min, {type} max) {{ if (x < min) {{return min;}} if (x > max) {{return max;}} return x; }}
|
||||||
@ -29,12 +31,21 @@ def gen_min_max_clamp(int_types: list, uint_types: list) -> str:
|
|||||||
|
|
||||||
result = "\n// Signed min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)\n"
|
result = "\n// Signed min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)\n"
|
||||||
for t in int_types:
|
for t in int_types:
|
||||||
|
if t.is_optional:
|
||||||
|
result += "#ifdef {int_max}\n".format(int_max = t.INT_MAX)
|
||||||
result += template.format(type = t.INT_TYPE, type_abbr = t.INT_TYPE_ABBR)
|
result += template.format(type = t.INT_TYPE, type_abbr = t.INT_TYPE_ABBR)
|
||||||
|
if t.is_optional:
|
||||||
|
result += "#endif\n"
|
||||||
|
result += "\n"
|
||||||
|
|
||||||
result += "\n// Unsigned min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)\n"
|
result += "\n// Unsigned min, max, clamp functions (generated with libguf/tools/min_max_clamp-gen.py)\n"
|
||||||
for t in uint_types:
|
for t in uint_types:
|
||||||
|
if t.is_optional:
|
||||||
|
result +="#ifdef {int_max}\n".format(int_max = t.INT_MAX)
|
||||||
result += template.format(type = t.INT_TYPE, type_abbr = t.INT_TYPE_ABBR)
|
result += template.format(type = t.INT_TYPE, type_abbr = t.INT_TYPE_ABBR)
|
||||||
|
if t.is_optional:
|
||||||
|
result += "#endif\n"
|
||||||
|
result += "\n"
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -46,14 +57,22 @@ if __name__ == "__main__":
|
|||||||
IntType(INT_TYPE = "long", INT_TYPE_ABBR = "long", INT_MIN = "LONG_MIN", INT_MAX = "LONG_MAX"),
|
IntType(INT_TYPE = "long", INT_TYPE_ABBR = "long", INT_MIN = "LONG_MIN", INT_MAX = "LONG_MAX"),
|
||||||
IntType(INT_TYPE = "long long", INT_TYPE_ABBR = "long_long", INT_MIN = "LLONG_MIN", INT_MAX = "LLONG_MAX"),
|
IntType(INT_TYPE = "long long", INT_TYPE_ABBR = "long_long", INT_MIN = "LLONG_MIN", INT_MAX = "LLONG_MAX"),
|
||||||
|
|
||||||
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX"),
|
|
||||||
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX"),
|
|
||||||
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX"),
|
|
||||||
IntType(INT_TYPE = "int64_t", INT_TYPE_ABBR = "i64", INT_MIN = "INT64_MIN", INT_MAX = "INT64_MAX"),
|
|
||||||
IntType(INT_TYPE = "ptrdiff_t", INT_TYPE_ABBR = "ptrdiff_t", INT_MIN = "PTRDIFF_MIN", INT_MAX = "PTRDIFF_MAX"),
|
IntType(INT_TYPE = "ptrdiff_t", INT_TYPE_ABBR = "ptrdiff_t", INT_MIN = "PTRDIFF_MIN", INT_MAX = "PTRDIFF_MAX"),
|
||||||
|
|
||||||
|
IntType(INT_TYPE = "int_fast8_t", INT_TYPE_ABBR = "i8_fast", INT_MIN = "GUF_INT8_MIN", INT_MAX = "GUF_INT8_MAX"),
|
||||||
|
IntType(INT_TYPE = "int_fast16_t", INT_TYPE_ABBR = "i16_fast", INT_MIN = "GUF_INT16_MIN", INT_MAX = "GUF_INT16_MAX"),
|
||||||
|
IntType(INT_TYPE = "int_fast32_t", INT_TYPE_ABBR = "i32_fast", INT_MIN = "GUF_INT32_MIN", INT_MAX = "GUF_INT32_MAX"),
|
||||||
|
IntType(INT_TYPE = "int_fast64_t", INT_TYPE_ABBR = "i64_fast", INT_MIN = "GUF_INT64_MIN", INT_MAX = "GUF_INT64_MAX"),
|
||||||
|
|
||||||
IntType(INT_TYPE = "float", INT_TYPE_ABBR = "f32", INT_MIN = "-FLT_MAX", INT_MAX = "FLT_MAX"),
|
IntType(INT_TYPE = "float", INT_TYPE_ABBR = "f32", INT_MIN = "-FLT_MAX", INT_MAX = "FLT_MAX"),
|
||||||
IntType(INT_TYPE = "double", INT_TYPE_ABBR = "f64", INT_MIN = "-DBL_MAX", INT_MAX = "DBL_MAX"),
|
IntType(INT_TYPE = "double", INT_TYPE_ABBR = "f64", INT_MIN = "-DBL_MAX", INT_MAX = "DBL_MAX"),
|
||||||
|
|
||||||
|
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX", is_optional=True),
|
||||||
|
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX", is_optional=True),
|
||||||
|
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX", is_optional=True),
|
||||||
|
IntType(INT_TYPE = "int64_t", INT_TYPE_ABBR = "i64", INT_MIN = "INT64_MIN", INT_MAX = "INT64_MAX", is_optional=True),
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
uint_types = [
|
uint_types = [
|
||||||
@ -62,11 +81,17 @@ if __name__ == "__main__":
|
|||||||
UintType(INT_TYPE = "unsigned long", INT_TYPE_ABBR = "ulong", INT_MIN = "0", INT_MAX = "ULONG_MAX"),
|
UintType(INT_TYPE = "unsigned long", INT_TYPE_ABBR = "ulong", INT_MIN = "0", INT_MAX = "ULONG_MAX"),
|
||||||
UintType(INT_TYPE = "unsigned long long", INT_TYPE_ABBR = "ulong_long", INT_MIN = "0", INT_MAX = "ULLONG_MAX"),
|
UintType(INT_TYPE = "unsigned long long", INT_TYPE_ABBR = "ulong_long", INT_MIN = "0", INT_MAX = "ULLONG_MAX"),
|
||||||
|
|
||||||
UintType(INT_TYPE = "uint8_t", INT_TYPE_ABBR = "u8", INT_MIN = "0", INT_MAX = "UINT8_MAX"),
|
|
||||||
UintType(INT_TYPE = "uint16_t", INT_TYPE_ABBR = "u16", INT_MIN = "0", INT_MAX = "UINT16_MAX"),
|
|
||||||
UintType(INT_TYPE = "uint32_t", INT_TYPE_ABBR = "u32", INT_MIN = "0", INT_MAX = "UINT32_MAX"),
|
|
||||||
UintType(INT_TYPE = "uint64_t", INT_TYPE_ABBR = "u64", INT_MIN = "0", INT_MAX = "UINT64_MAX"),
|
|
||||||
UintType(INT_TYPE = "size_t", INT_TYPE_ABBR = "size_t", INT_MIN = "0", INT_MAX = "SIZE_MAX"),
|
UintType(INT_TYPE = "size_t", INT_TYPE_ABBR = "size_t", INT_MIN = "0", INT_MAX = "SIZE_MAX"),
|
||||||
|
|
||||||
|
UintType(INT_TYPE = "uint_fast8_t", INT_TYPE_ABBR = "u8_fast", INT_MIN = "0", INT_MAX = "GUF_UINT8_MAX"),
|
||||||
|
UintType(INT_TYPE = "uint_fast16_t", INT_TYPE_ABBR = "u16_fast", INT_MIN = "0", INT_MAX = "GUF_UINT16_MAX"),
|
||||||
|
UintType(INT_TYPE = "uint_fast32_t", INT_TYPE_ABBR = "u32_fast", INT_MIN = "0", INT_MAX = "GUF_UINT32_MAX"),
|
||||||
|
UintType(INT_TYPE = "uint_fast64_t", INT_TYPE_ABBR = "u64_fast", INT_MIN = "0", INT_MAX = "GUF_UINT64_MAX"),
|
||||||
|
|
||||||
|
UintType(INT_TYPE = "uint8_t", INT_TYPE_ABBR = "u8", INT_MIN = "0", INT_MAX = "UINT8_MAX", is_optional=True),
|
||||||
|
UintType(INT_TYPE = "uint16_t", INT_TYPE_ABBR = "u16", INT_MIN = "0", INT_MAX = "UINT16_MAX", is_optional=True),
|
||||||
|
UintType(INT_TYPE = "uint32_t", INT_TYPE_ABBR = "u32", INT_MIN = "0", INT_MAX = "UINT32_MAX", is_optional=True),
|
||||||
|
UintType(INT_TYPE = "uint64_t", INT_TYPE_ABBR = "u64", INT_MIN = "0", INT_MAX = "UINT64_MAX", is_optional=True),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user