summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/kit.inl.h2870
1 files changed, 2696 insertions, 174 deletions
diff --git a/include/kit.inl.h b/include/kit.inl.h
index 44d22eb..06eaafd 100644
--- a/include/kit.inl.h
+++ b/include/kit.inl.h
@@ -2,7 +2,25 @@
#define KIT_INL_H
/*********************************************************************
* *
- * File: ./source/kit/status.h *
+ * File: source/kit/types.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_TYPES_H
+#define KIT_TYPES_H
+typedef signed char i8;
+typedef signed short i16;
+typedef signed int i32;
+typedef signed long long i64;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+typedef float f32;
+typedef double f64;
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/status.h *
* *
*********************************************************************/
#ifndef KIT_STATUS_H
@@ -18,20 +36,25 @@ enum {
KIT_ERROR_UNLINK_FAILED,
KIT_ERROR_FILE_ALREADY_EXISTS,
KIT_ERROR_FILE_DO_NOT_EXIST,
- KIT_ERROR_PATH_TOO_LONG
+ KIT_ERROR_PATH_TOO_LONG,
+ KIT_ERROR_SOCKETS_STARTUP_FAILED,
+ KIT_ERROR_SOCKET_CONTROL_FAILED
};
-typedef int kit_status_t;
+typedef signed int kit_status_t;
#ifdef __cplusplus
}
#endif
#endif
/*********************************************************************
* *
- * File: ./source/kit/allocator.h *
+ * File: source/kit/allocator.h *
* *
*********************************************************************/
#ifndef KIT_ALLOCATOR_H
#define KIT_ALLOCATOR_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
@@ -48,7 +71,7 @@ typedef struct {
/* Application should implement this function if custom allocator
* dispatch is enabled.
*
- * See KIT_ENABLE_CUSTOM_ALLOC_DISPATCH
+ * See KIT_ENABLE_CUSTOM_ALLOC_DISPATCH macro.
*/
void *kit_alloc_dispatch(kit_allocator_t alloc, int request,
ptrdiff_t size, ptrdiff_t previous_size,
@@ -60,47 +83,367 @@ kit_allocator_t kit_alloc_default(void);
#endif
/*********************************************************************
* *
- * File: ./source/kit/array_ref.h *
+ * File: source/kit/thread_defs.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_THREAD_DEFS_H
+#define KIT_THREAD_DEFS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+enum {
+ thrd_success = 0,
+ thrd_timedout,
+ thrd_error,
+ thrd_busy,
+ thrd_nomem,
+ thrd_wrong_stack_size
+};
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/thread.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_THREAD_H
+#define KIT_THREAD_H
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+# include <stddef.h>
+# include <time.h>
+# if defined(__cplusplus)
+# define _Noreturn [[noreturn]]
+# elif defined(_MSC_VER)
+# define _Noreturn __declspec(noreturn)
+# endif
+# if !defined(_WIN32) || defined(__CYGWIN__)
+# include <pthread.h>
+# endif
+# ifndef _Thread_local
+# if defined(__cplusplus)
+/* C++11 doesn't need `_Thread_local` keyword or macro */
+# elif !defined(__STDC_NO_THREADS__)
+/* threads are optional in C11, _Thread_local present in this
+ * condition */
+# elif defined(_MSC_VER)
+# define _Thread_local __declspec(thread)
+# elif defined(__GNUC__)
+# define _Thread_local __thread
+# else
+/* Leave _Thread_local undefined so that use of _Thread_local would
+ * not promote to a non-thread-local global variable
+ */
+# endif
+# endif
+# if !defined(__cplusplus)
+/*
+ * C11 thread_local() macro
+ * C++11 and above already have thread_local keyword
+ */
+# ifndef thread_local
+# if _MSC_VER
+# define thread_local __declspec(thread)
+# else
+# define thread_local _Thread_local
+# endif
+# endif
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif
+typedef void (*tss_dtor_t)(void *);
+typedef int (*thrd_start_t)(void *);
+# if defined(_WIN32) && !defined(__CYGWIN__)
+typedef struct {
+ void *handle;
+} thrd_t;
+typedef unsigned long tss_t;
+# else
+typedef pthread_t thrd_t;
+typedef pthread_key_t tss_t;
+# endif
+int thrd_create(thrd_t *, thrd_start_t, void *);
+int thrd_create_with_stack(thrd_t *, thrd_start_t, void *,
+ ptrdiff_t stack_size);
+thrd_t thrd_current(void);
+int thrd_detach(thrd_t);
+int thrd_equal(thrd_t, thrd_t);
+_Noreturn void thrd_exit(int);
+int thrd_join(thrd_t, int *);
+int thrd_sleep(const struct timespec *, struct timespec *);
+void thrd_yield(void);
+# ifdef __cplusplus
+}
+# endif
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/atomic.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_ATOMIC_H
+#define KIT_ATOMIC_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <stdint.h>
+#ifndef _MSC_VER
+# include <stdatomic.h>
+# define KIT_ATOMIC(type_) type_ _Atomic
+#else
+# include <assert.h>
+# define KIT_ATOMIC(type_) type_ volatile
+# ifdef __cplusplus
+extern "C" {
+# endif
+enum {
+ memory_order_relaxed,
+ memory_order_consume,
+ memory_order_acquire,
+ memory_order_release,
+ memory_order_acq_rel,
+ memory_order_seq_cst
+};
+void kit_atomic_store_explicit_8(uint8_t volatile *var, uint8_t value,
+ int memory_order);
+void kit_atomic_store_explicit_16(uint16_t volatile *var,
+ uint16_t value, int memory_order);
+void kit_atomic_store_explicit_32(uint32_t volatile *var,
+ uint32_t value, int memory_order);
+void kit_atomic_store_explicit_64(uint64_t volatile *var,
+ uint64_t value, int memory_order);
+uint8_t kit_atomic_load_explicit_8(uint8_t volatile *var,
+ int memory_order);
+uint16_t kit_atomic_load_explicit_16(uint16_t volatile *var,
+ int memory_order);
+uint32_t kit_atomic_load_explicit_32(uint32_t volatile *var,
+ int memory_order);
+uint64_t kit_atomic_load_explicit_64(uint64_t volatile *var,
+ int memory_order);
+uint8_t kit_atomic_exchange_explicit_8(uint8_t volatile *var,
+ uint8_t value,
+ int memory_order);
+uint16_t kit_atomic_exchange_explicit_16(uint16_t volatile *var,
+ uint16_t value,
+ int memory_order);
+uint32_t kit_atomic_exchange_explicit_32(uint32_t volatile *var,
+ uint32_t value,
+ int memory_order);
+uint64_t kit_atomic_exchange_explicit_64(uint64_t volatile *var,
+ uint64_t value,
+ int memory_order);
+uint8_t kit_atomic_fetch_add_explicit_8(uint8_t volatile *var,
+ uint8_t value,
+ int memory_order);
+uint16_t kit_atomic_fetch_add_explicit_16(uint16_t volatile *var,
+ uint16_t value,
+ int memory_order);
+uint32_t kit_atomic_fetch_add_explicit_32(uint32_t volatile *var,
+ uint32_t value,
+ int memory_order);
+uint64_t kit_atomic_fetch_add_explicit_64(uint64_t volatile *var,
+ uint64_t value,
+ int memory_order);
+# define atomic_store_explicit(var_, value_, memory_order_) \
+ do { \
+ assert(sizeof *(var_) == 1 || sizeof *(var_) == 2 || \
+ sizeof *(var_) == 4 || sizeof *(var_) == 8); \
+ if (sizeof *(var_) == 1) \
+ kit_atomic_store_explicit_8((uint8_t volatile *) (var_), \
+ (uint8_t) (value_), \
+ (memory_order_)); \
+ if (sizeof *(var_) == 2) \
+ kit_atomic_store_explicit_16((uint16_t volatile *) (var_), \
+ (uint16_t) (value_), \
+ (memory_order_)); \
+ if (sizeof *(var_) == 4) \
+ kit_atomic_store_explicit_32((uint32_t volatile *) (var_), \
+ (uint32_t) (value_), \
+ (memory_order_)); \
+ if (sizeof *(var_) == 8) \
+ kit_atomic_store_explicit_64((uint64_t volatile *) (var_), \
+ (uint64_t) (value_), \
+ (memory_order_)); \
+ } while (0)
+# define atomic_load_explicit(var_, memory_order_) \
+ (assert(sizeof *(var_) == 1 || sizeof *(var_) == 2 || \
+ sizeof *(var_) == 4 || sizeof *(var_) == 8), \
+ (sizeof *(var_) == 1 \
+ ? kit_atomic_load_explicit_8((uint8_t volatile *) (var_), \
+ (memory_order_)) \
+ : sizeof *(var_) == 2 \
+ ? kit_atomic_load_explicit_16( \
+ (uint16_t volatile *) (var_), (memory_order_)) \
+ : sizeof *(var_) == 4 \
+ ? kit_atomic_load_explicit_32( \
+ (uint32_t volatile *) (var_), (memory_order_)) \
+ : kit_atomic_load_explicit_64( \
+ (uint64_t volatile *) (var_), (memory_order_))))
+# define atomic_exchange_explicit(var_, value_, memory_order_) \
+ (assert(sizeof *(var_) == 1 || sizeof *(var_) == 2 || \
+ sizeof *(var_) == 4 || sizeof *(var_) == 8), \
+ (sizeof *(var_) == 1 ? kit_atomic_exchange_explicit_8( \
+ (uint8_t volatile *) (var_), \
+ (uint8_t) (value_), (memory_order_)) \
+ : sizeof *(var_) == 2 \
+ ? kit_atomic_exchange_explicit_16( \
+ (uint16_t volatile *) (var_), (uint16_t) (value_), \
+ (memory_order_)) \
+ : sizeof *(var_) == 4 \
+ ? kit_atomic_exchange_explicit_32( \
+ (uint32_t volatile *) (var_), (uint32_t) (value_), \
+ (memory_order_)) \
+ : kit_atomic_exchange_explicit_64( \
+ (uint64_t volatile *) (var_), (uint64_t) (value_), \
+ (memory_order_))))
+# define atomic_fetch_add_explicit(var_, value_, memory_order_) \
+ (assert(sizeof *(var_) == 1 || sizeof *(var_) == 2 || \
+ sizeof *(var_) == 4 || sizeof *(var_) == 8), \
+ (sizeof *(var_) == 1 ? kit_atomic_fetch_add_explicit_8( \
+ (uint8_t volatile *) (var_), \
+ (uint8_t) (value_), (memory_order_)) \
+ : sizeof *(var_) == 2 \
+ ? kit_atomic_fetch_add_explicit_16( \
+ (uint16_t volatile *) (var_), (uint16_t) (value_), \
+ (memory_order_)) \
+ : sizeof *(var_) == 4 \
+ ? kit_atomic_fetch_add_explicit_32( \
+ (uint32_t volatile *) (var_), (uint32_t) (value_), \
+ (memory_order_)) \
+ : kit_atomic_fetch_add_explicit_64( \
+ (uint64_t volatile *) (var_), (uint64_t) (value_), \
+ (memory_order_))))
+#endif
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define ATOMIC KIT_ATOMIC
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/mutex.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_MUTEX_H
+#define KIT_MUTEX_H
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+# include <time.h>
+# if !defined(_WIN32) || defined(__CYGWIN__)
+# include <pthread.h>
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif
+# if defined(_WIN32) && !defined(__CYGWIN__)
+typedef struct {
+ void *DebugInfo;
+ long LockCount;
+ long RecursionCount;
+ void *OwningThread;
+ void *LockSemaphore;
+ uintptr_t SpinCount;
+} mtx_t;
+# else
+typedef pthread_mutex_t mtx_t;
+# endif
+enum {
+ mtx_plain = 0,
+ mtx_recursive = 1,
+ mtx_timed = 2,
+};
+void mtx_destroy(mtx_t *mtx_);
+int mtx_init(mtx_t *mtx_, int);
+int mtx_lock(mtx_t *mtx_);
+int mtx_timedlock(mtx_t *__restrict mtx_,
+ struct timespec const *__restrict);
+int mtx_trylock(mtx_t *mtx_);
+int mtx_unlock(mtx_t *mtx_);
+# ifdef __cplusplus
+}
+# endif
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/condition_variable.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_CONDITION_VARIABLE_H
+#define KIT_CONDITION_VARIABLE_H
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+# ifdef __cplusplus
+extern "C" {
+# endif
+# if defined(_WIN32) && !defined(__CYGWIN__)
+typedef struct {
+ void *Ptr;
+} cnd_t;
+typedef struct {
+ volatile uintptr_t status;
+} once_flag;
+# else
+typedef pthread_cond_t cnd_t;
+typedef pthread_once_t once_flag;
+# endif
+void call_once(once_flag *, void (*)(void));
+int cnd_broadcast(cnd_t *);
+void cnd_destroy(cnd_t *);
+int cnd_init(cnd_t *);
+int cnd_signal(cnd_t *);
+int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict mtx_,
+ struct timespec const *__restrict);
+int cnd_wait(cnd_t *, mtx_t *mtx_);
+# ifdef __cplusplus
+}
+# endif
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/array_ref.h *
* *
*********************************************************************/
#ifndef KIT_ARRAY_REF_H
#define KIT_ARRAY_REF_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
-typedef int (*kit_ar_compare_fn)(void const *left, void const *right);
+typedef int (*kit_ar_compare_fn)(void *left, void *right);
int kit_ar_equal_bytes(ptrdiff_t left_element_size,
- ptrdiff_t left_size, void const *left_data,
+ ptrdiff_t left_size, void *left_data,
ptrdiff_t right_element_size,
- ptrdiff_t right_size, void const *right_data);
+ ptrdiff_t right_size, void *right_data);
int kit_ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size,
- void const *left_data,
- ptrdiff_t right_element_size, ptrdiff_t right_size,
- void const *right_data, kit_ar_compare_fn compare);
-#define KIT_AR_MUT(type_) \
- struct { \
- ptrdiff_t size; \
- type_ *values; \
- }
+ void *left_data, ptrdiff_t right_element_size,
+ ptrdiff_t right_size, void *right_data,
+ kit_ar_compare_fn compare);
#define KIT_AR(type_) \
- struct { \
- ptrdiff_t size; \
- type_ const *values; \
+ struct { \
+ ptrdiff_t size; \
+ type_ *values; \
}
-#define KIT_AR_MUT_WRAP(name_, element_type_, array_) \
+#define KIT_AR_WRAP(name_, element_type_, array_) \
struct { \
ptrdiff_t size; \
element_type_ *values; \
} name_ = { .size = (sizeof(array_) / sizeof((array_)[0])), \
.values = (array_) }
-#define KIT_AR_WRAP(name_, element_type_, array_) \
- struct { \
- ptrdiff_t size; \
- element_type_ const *values; \
- } name_ = { .size = (sizeof(array_) / sizeof((array_)[0])), \
- .values = (array_) }
#define KIT_AR_EQUAL(left_, right_) \
kit_ar_equal_bytes(sizeof((left_).values[0]), (left_).size, \
(left_).values, sizeof((right_).values[0]), \
@@ -114,9 +457,7 @@ int kit_ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size,
# define ar_compare_fn kit_ar_compare_fn
# define ar_equal_bytes kit_ar_equal_bytes
# define ar_compare kit_ar_compare
-# define AR_MUT KIT_AR_MUT
# define AR KIT_AR
-# define AR_MUT_WRAP KIT_AR_MUT_WRAP
# define AR_WRAP KIT_AR_WRAP
# define AR_EQUAL KIT_AR_EQUAL
# define AR_COMPARE KIT_AR_COMPARE
@@ -127,7 +468,68 @@ int kit_ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size,
#endif
/*********************************************************************
* *
- * File: ./source/kit/dynamic_array.h *
+ * File: source/kit/string_ref.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_STRING_REF_H
+#define KIT_STRING_REF_H
+#include <string.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef KIT_AR(char) kit_string_ref_t;
+typedef kit_string_ref_t kit_str_t;
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-function"
+# pragma GCC diagnostic ignored "-Wunknown-pragmas"
+# pragma GCC push_options
+# pragma GCC optimize("O3")
+#endif
+static kit_str_t kit_str(ptrdiff_t size, char *static_string) {
+ kit_str_t s = { .size = size, .values = static_string };
+ return s;
+}
+/* Make a barbarian string for C standard library functions.
+ * Not thread safe.
+ * Use with caution.
+ */
+static char *kit_make_bs(kit_str_t s) {
+ static char buf[8][4096];
+ static int index = 0;
+ ptrdiff_t n = s.size;
+ if (n > 4095)
+ n = 4095;
+ memcpy(buf[index], s.values, n);
+ buf[index][n] = '\0';
+ char *result = buf[index];
+ index = (index + 1) % 8;
+ return result;
+}
+#ifdef __GNUC__
+# pragma GCC pop_options
+# pragma GCC diagnostic pop
+#endif
+#define KIT_SZ(static_str_) \
+ kit_str(sizeof(static_str_) - 1, (static_str_))
+#define KIT_WRAP_BS(string_) kit_str(strlen(string_), (string_))
+#define KIT_WRAP_STR(string_) \
+ kit_str((string_).size, (string_).values)
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define BS(string_) kit_make_bs(KIT_WRAP_STR(string_))
+# define string_ref_t kit_string_ref_t
+# define str_t kit_str_t
+# define SZ KIT_SZ
+# define WRAP_BS KIT_WRAP_BS
+# define WRAP_STR KIT_WRAP_STR
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/dynamic_array.h *
* *
*********************************************************************/
#ifndef KIT_DYNAMIC_ARRAY_H
@@ -179,20 +581,20 @@ void kit_da_resize(kit_da_void_t *array, ptrdiff_t element_size,
sizeof((array_).values[0]), size_)
/* Append a value to dynamic array.
*/
-#define KIT_DA_APPEND(array_, value_) \
- do { \
- ptrdiff_t const kit_index_back_ = (array_).size; \
- KIT_DA_RESIZE((array_), kit_index_back_ + 1); \
- if (kit_index_back_ < (array_).size) \
- (array_).values[kit_index_back_] = (value_); \
+#define KIT_DA_APPEND(array_, value_) \
+ do { \
+ ptrdiff_t kit_index_back_ = (array_).size; \
+ KIT_DA_RESIZE((array_), kit_index_back_ + 1); \
+ if (kit_index_back_ < (array_).size) \
+ (array_).values[kit_index_back_] = (value_); \
} while (0)
/* Insert a value into dynamic array.
*/
#define KIT_DA_INSERT(array_, index_, value_) \
do { \
- ptrdiff_t kit_i_; \
- ptrdiff_t const kit_index_back_ = (array_).size; \
- ptrdiff_t const kit_indert_n_ = (index_); \
+ ptrdiff_t kit_i_; \
+ ptrdiff_t kit_index_back_ = (array_).size; \
+ ptrdiff_t kit_indert_n_ = (index_); \
KIT_DA_RESIZE((array_), kit_index_back_ + 1); \
if (kit_index_back_ + 1 == (array_).size) { \
for (kit_i_ = kit_index_back_; kit_i_ > kit_indert_n_; \
@@ -231,19 +633,121 @@ typedef KIT_DA(char) kit_string_t;
#endif
/*********************************************************************
* *
- * File: ./source/kit/string_ref.h *
+ * File: source/kit/lower_bound.h *
* *
*********************************************************************/
-#ifndef KIT_STRING_REF_H
-#define KIT_STRING_REF_H
+#ifndef KIT_LOWER_BOUND_H
+#define KIT_LOWER_BOUND_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define KIT_LOWER_BOUND_INL(return_val, size, ...) \
+ do { \
+ ptrdiff_t position_ = 0; \
+ ptrdiff_t count_ = (size); \
+ while (count_ > 0) { \
+ ptrdiff_t const delta_ = count_ / 2; \
+ ptrdiff_t const index_ = position_ + delta_; \
+ if (__VA_ARGS__) { \
+ position_ += delta_ + 1; \
+ count_ -= delta_ + 1; \
+ } else \
+ count_ = delta_; \
+ } \
+ (return_val) = position_; \
+ } while (0)
+#define KIT_LOWER_BOUND(return_val, array, value, op) \
+ KIT_LOWER_BOUND_INL(return_val, (array).size, \
+ (op) ((array).values[index_], (value)))
+#define KIT_LOWER_BOUND_REF(return_val, array, value, op) \
+ KIT_LOWER_BOUND_INL(return_val, (array).size, \
+ (op) ((array).values + index_, (value)))
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define LOWER_BOUND_INL KIT_LOWER_BOUND_INL
+# define LOWER_BOUND KIT_LOWER_BOUND
+# define LOWER_BOUND_REF KIT_LOWER_BOUND_REF
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/move_back.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_MOVE_BACK_H
+#define KIT_MOVE_BACK_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
-typedef KIT_AR_MUT(char) kit_string_mut_t;
-typedef KIT_AR(char) kit_string_ref_t;
-typedef kit_string_mut_t kit_out_str_t;
-typedef kit_string_ref_t kit_str_t;
+#define KIT_MOVE_BACK_INL(new_size, array, ...) \
+ do { \
+ ptrdiff_t index_; \
+ ptrdiff_t end_ = (array).size; \
+ unsigned char temp_[sizeof *(array).values]; \
+ for (index_ = 0; index_ < end_;) { \
+ if (__VA_ARGS__) { \
+ end_--; \
+ if (index_ != end_) { \
+ memcpy(temp_, (array).values + end_, \
+ sizeof *(array).values); \
+ (array).values[end_] = (array).values[index_]; \
+ memcpy((array).values + index_, temp_, \
+ sizeof *(array).values); \
+ } \
+ } else \
+ index_++; \
+ } \
+ (new_size) = end_; \
+ } while (0)
+#define KIT_MOVE_BACK(new_size, array, value, cond) \
+ KIT_MOVE_BACK_INL(new_size, array, \
+ (cond) ((array).values[index_], (value)))
+#define KIT_MOVE_BACK_REF(new_size, array, value, cond) \
+ KIT_MOVE_BACK_INL(new_size, array, \
+ (cond) ((array).values + index_, (value)))
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define MOVE_BACK_INL KIT_MOVE_BACK_INL
+# define MOVE_BACK KIT_MOVE_BACK
+# define MOVE_BACK_REF KIT_MOVE_BACK_REF
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/bigint.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_BIGINT_H
+#define KIT_BIGINT_H
+#include <assert.h>
+#include <string.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifndef KIT_BIGINT_SIZE
+# define KIT_BIGINT_SIZE 64
+#endif
+#if __STDC_VERSION__ >= 199901L
+static_assert(sizeof(uint8_t) == 1, "uint8_t size should be 1 byte");
+static_assert(sizeof(uint32_t) == 4,
+ "uint32_t size should be 4 bytes");
+static_assert(sizeof(uint64_t) == 8,
+ "uint64_t size should be 8 bytes");
+static_assert(KIT_BIGINT_SIZE > 0 && (KIT_BIGINT_SIZE % 8) == 0,
+ "Invalid big integer size");
+#endif
+typedef struct {
+ uint32_t v[KIT_BIGINT_SIZE / 4];
+} kit_bigint_t;
+typedef uint_fast8_t kit_bit_t;
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
@@ -251,45 +755,735 @@ typedef kit_string_ref_t kit_str_t;
# pragma GCC push_options
# pragma GCC optimize("O3")
#endif
-static kit_str_t kit_str(ptrdiff_t const size,
- char const *const static_string) {
- kit_str_t const s = { .size = size, .values = static_string };
- return s;
+static kit_bigint_t kit_bi_uint32(uint32_t x) {
+ kit_bigint_t z;
+ memset(&z, 0, sizeof z);
+ z.v[0] = x;
+ return z;
}
-/* Make a barbarian string for C standard library functions.
- * Not thread safe.
- * Use with caution.
+static kit_bigint_t kit_bi_uint64(uint64_t x) {
+ kit_bigint_t z;
+ memset(&z, 0, sizeof z);
+ z.v[0] = (uint32_t) (x & 0xffffffff);
+ z.v[1] = (uint32_t) (x >> 32);
+ return z;
+}
+static kit_bigint_t kit_bi_int32(int32_t x) {
+ kit_bigint_t z;
+ memset(&z, x < 0 ? -1 : 0, sizeof z);
+ z.v[0] = x;
+ return z;
+}
+static kit_bigint_t kit_bi_int64(int64_t x) {
+ kit_bigint_t z;
+ memset(&z, x < 0 ? -1 : 0, sizeof z);
+ z.v[0] = (uint32_t) (((uint64_t) x) & 0xffffffff);
+ z.v[1] = (uint32_t) (((uint64_t) x) >> 32);
+ return z;
+}
+static int kit_bi_is_zero(kit_bigint_t x) {
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++)
+ if (x.v[i] != 0)
+ return 0;
+ return 1;
+}
+static int kit_bi_is_neg(kit_bigint_t x) {
+ return (x.v[KIT_BIGINT_SIZE / 4 - 1] & 0x80000000) != 0;
+}
+static int kit_bi_equal(kit_bigint_t x, kit_bigint_t y) {
+ return kit_ar_equal_bytes(1, KIT_BIGINT_SIZE, x.v, 1,
+ KIT_BIGINT_SIZE, y.v);
+}
+static int kit_bi_compare(kit_bigint_t x, kit_bigint_t y) {
+ ptrdiff_t i;
+ for (i = KIT_BIGINT_SIZE / 4 - 1; i >= 0; i--)
+ if (x.v[i] < y.v[i])
+ return -1;
+ else if (x.v[i] > y.v[i])
+ return 1;
+ return 0;
+}
+static ptrdiff_t kit_bi_significant_bit_count(kit_bigint_t x) {
+ ptrdiff_t n = KIT_BIGINT_SIZE / 4 - 1;
+ while (n > 0 && x.v[n] == 0) n--;
+ uint32_t val = x.v[n];
+ if (val == 0)
+ return 0;
+ ptrdiff_t bits = (val & 0x80000000u) != 0 ? 32
+ : (val & 0x40000000u) != 0 ? 31
+ : (val & 0x20000000u) != 0 ? 30
+ : (val & 0x10000000u) != 0 ? 29
+ : (val & 0x8000000u) != 0 ? 28
+ : (val & 0x4000000u) != 0 ? 27
+ : (val & 0x2000000u) != 0 ? 26
+ : (val & 0x1000000u) != 0 ? 25
+ : (val & 0x800000u) != 0 ? 24
+ : (val & 0x400000u) != 0 ? 23
+ : (val & 0x200000u) != 0 ? 22
+ : (val & 0x100000u) != 0 ? 21
+ : (val & 0x80000u) != 0 ? 20
+ : (val & 0x40000u) != 0 ? 19
+ : (val & 0x20000u) != 0 ? 18
+ : (val & 0x10000u) != 0 ? 17
+ : (val & 0x8000u) != 0 ? 16
+ : (val & 0x4000u) != 0 ? 15
+ : (val & 0x2000u) != 0 ? 14
+ : (val & 0x1000u) != 0 ? 13
+ : (val & 0x800u) != 0 ? 12
+ : (val & 0x400u) != 0 ? 11
+ : (val & 0x200u) != 0 ? 10
+ : (val & 0x100u) != 0 ? 9
+ : (val & 0x80u) != 0 ? 8
+ : (val & 0x40u) != 0 ? 7
+ : (val & 0x20u) != 0 ? 6
+ : (val & 0x10u) != 0 ? 5
+ : (val & 0x08u) != 0 ? 4
+ : (val & 0x04u) != 0 ? 3
+ : (val & 0x02u) != 0 ? 2
+ : 1;
+ return n * 32 + bits;
+}
+static kit_bigint_t kit_bi_and(kit_bigint_t x, kit_bigint_t y) {
+ kit_bigint_t z;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) z.v[i] = x.v[i] & y.v[i];
+ return z;
+}
+static kit_bigint_t kit_bi_or(kit_bigint_t x, kit_bigint_t y) {
+ kit_bigint_t z;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) z.v[i] = x.v[i] | y.v[i];
+ return z;
+}
+static kit_bigint_t kit_bi_xor(kit_bigint_t x, kit_bigint_t y) {
+ kit_bigint_t z;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) z.v[i] = x.v[i] ^ y.v[i];
+ return z;
+}
+static kit_bigint_t kit_bi_shl_uint(kit_bigint_t x, uint32_t y) {
+ kit_bigint_t z;
+ memset(&z, 0, sizeof z);
+ ptrdiff_t words = (ptrdiff_t) (y / 32);
+ ptrdiff_t bits = (ptrdiff_t) (y % 32);
+ ptrdiff_t i;
+ for (i = words; i < KIT_BIGINT_SIZE / 4; i++) {
+ z.v[i] |= x.v[i - words] << bits;
+ if (bits != 0 && i + 1 < KIT_BIGINT_SIZE / 4)
+ z.v[i + 1] = x.v[i - words] >> (32 - bits);
+ }
+ return z;
+}
+static kit_bigint_t kit_bi_shr_uint(kit_bigint_t x, uint32_t y) {
+ kit_bigint_t z;
+ memset(&z, 0, sizeof z);
+ ptrdiff_t words = (ptrdiff_t) (y / 32);
+ ptrdiff_t bits = (ptrdiff_t) (y % 32);
+ ptrdiff_t i;
+ for (i = KIT_BIGINT_SIZE / 4 - words - 1; i >= 0; i--) {
+ z.v[i] |= x.v[i + words] >> bits;
+ if (bits != 0 && i > 0)
+ z.v[i - 1] = x.v[i + words] << (32 - bits);
+ }
+ return z;
+}
+static kit_bit_t kit_bi_carry(uint32_t x, uint32_t y,
+ kit_bit_t carry) {
+ assert(carry == 0 || carry == 1);
+ return 0xffffffffu - x < y || 0xffffffffu - x - y < carry ? 1 : 0;
+}
+/* Increment.
*/
-static char const *kit_make_bs(kit_str_t const s) {
- static char buf[8][4096];
- static int index = 0;
- ptrdiff_t n = s.size;
- if (n > 4095)
- n = 4095;
- memcpy(buf[index], s.values, n);
- buf[index][n] = '\0';
- char const *result = buf[index];
- index = (index + 1) % 8;
- return result;
+static kit_bigint_t kit_bi_inc(kit_bigint_t x) {
+ kit_bigint_t z;
+ kit_bit_t carry = 1;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ z.v[i] = x.v[i] + carry;
+ carry = kit_bi_carry(x.v[i], 0, carry);
+ }
+ return z;
+}
+/* Decrement
+ */
+static kit_bigint_t kit_bi_dec(kit_bigint_t x) {
+ kit_bigint_t z;
+ kit_bit_t carry = 0;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ z.v[i] = x.v[i] + 0xffffffff + carry;
+ carry = kit_bi_carry(x.v[i], 0xffffffff, carry);
+ }
+ return z;
+}
+/* Addition.
+ */
+static kit_bigint_t kit_bi_add(kit_bigint_t x, kit_bigint_t y) {
+ kit_bigint_t z;
+ kit_bit_t carry = 0;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ z.v[i] = x.v[i] + y.v[i] + carry;
+ carry = kit_bi_carry(x.v[i], y.v[i], carry);
+ }
+ return z;
+}
+/* Negation.
+ */
+static kit_bigint_t kit_bi_neg(kit_bigint_t x) {
+ kit_bigint_t y;
+ kit_bit_t carry = 1;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ y.v[i] = (x.v[i] ^ 0xffffffff) + carry;
+ carry = kit_bi_carry(x.v[i] ^ 0xffffffff, 0, carry);
+ }
+ return y;
+}
+/* Subtraction.
+ */
+static kit_bigint_t kit_bi_sub(kit_bigint_t x, kit_bigint_t y) {
+ kit_bigint_t z;
+ kit_bit_t carry = 1;
+ ptrdiff_t i;
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ z.v[i] = x.v[i] + (y.v[i] ^ 0xffffffff) + carry;
+ carry = kit_bi_carry(x.v[i], (y.v[i] ^ 0xffffffff), carry);
+ }
+ return z;
+}
+static kit_bigint_t kit_bi_mul_uint32(kit_bigint_t x, uint32_t y) {
+ kit_bigint_t z;
+ ptrdiff_t i, k;
+ memset(&z, 0, sizeof z);
+ if (y != 0)
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ if (x.v[i] == 0)
+ continue;
+ uint64_t carry = ((uint64_t) x.v[i]) * ((uint64_t) y);
+ for (k = i; k < KIT_BIGINT_SIZE / 4 && carry != 0; k++) {
+ uint64_t sum = ((uint64_t) z.v[k]) + carry;
+ z.v[k] = ((uint32_t) (sum & 0xffffffffull));
+ carry = sum >> 32;
+ }
+ }
+ return z;
+}
+/* Multiplication.
+ */
+static kit_bigint_t kit_bi_mul(kit_bigint_t x, kit_bigint_t y) {
+ kit_bigint_t z;
+ ptrdiff_t i, j, k;
+ memset(&z, 0, sizeof z);
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ if (x.v[i] == 0)
+ continue;
+ for (j = 0; i + j < KIT_BIGINT_SIZE / 4; j++) {
+ if (y.v[j] == 0)
+ continue;
+ uint64_t carry = ((uint64_t) x.v[i]) * ((uint64_t) y.v[j]);
+ for (k = i + j; k < KIT_BIGINT_SIZE / 4 && carry != 0; k++) {
+ uint64_t sum = ((uint64_t) z.v[k]) + carry;
+ z.v[k] = ((uint32_t) (sum & 0xffffffffull));
+ carry = sum >> 32;
+ }
+ }
+ }
+ return z;
+}
+typedef struct {
+ kit_bit_t undefined;
+ kit_bigint_t quotient;
+ kit_bigint_t remainder;
+} kit_bi_division_t;
+/* Unsigned division.
+ */
+static kit_bi_division_t kit_bi_udiv(kit_bigint_t x, kit_bigint_t y) {
+ kit_bi_division_t z;
+ memset(&z, 0, sizeof z);
+ ptrdiff_t y_bits = kit_bi_significant_bit_count(y);
+ if (y_bits == 0) {
+ z.undefined = 1;
+ return z;
+ }
+ ptrdiff_t x_bits = kit_bi_significant_bit_count(x);
+ ptrdiff_t shift = x_bits - y_bits;
+ z.remainder = x;
+ z.quotient = kit_bi_uint32(0);
+ y = kit_bi_shl_uint(y, (uint32_t) shift);
+ while (shift >= 0) {
+ if (kit_bi_compare(z.remainder, y) >= 0) {
+ z.remainder = kit_bi_sub(z.remainder, y);
+ z.quotient.v[shift / 32] |= (1u << (shift % 32));
+ }
+ y = kit_bi_shr_uint(y, 1);
+ shift--;
+ }
+ return z;
+}
+/* Signed division.
+ *
+ * Remainder is always a non-negative value less than absolute value
+ * of y.
+ */
+static kit_bi_division_t kit_bi_div(kit_bigint_t x, kit_bigint_t y) {
+ int x_neg = kit_bi_is_neg(x);
+ int y_neg = kit_bi_is_neg(y);
+ kit_bigint_t x_abs = x_neg ? kit_bi_neg(x) : x;
+ kit_bigint_t y_abs = y_neg ? kit_bi_neg(y) : y;
+ if (x_neg == y_neg)
+ return kit_bi_udiv(x_abs, y_abs);
+ kit_bi_division_t z = kit_bi_udiv(x_abs, y_abs);
+ if (!kit_bi_is_zero(z.remainder) && !y_neg)
+ z.quotient = kit_bi_dec(kit_bi_neg(z.quotient));
+ else
+ z.quotient = kit_bi_neg(z.quotient);
+ return z;
+}
+static void kit_bi_serialize(kit_bigint_t in, uint8_t *out) {
+ ptrdiff_t i;
+ assert(out != NULL);
+ for (i = 0; i < KIT_BIGINT_SIZE / 4; i++) {
+ out[i * 4] = (uint8_t) (in.v[i] & 0xff);
+ out[i * 4 + 1] = (uint8_t) ((in.v[i] >> 8) & 0xff);
+ out[i * 4 + 2] = (uint8_t) ((in.v[i] >> 16) & 0xff);
+ out[i * 4 + 3] = (uint8_t) ((in.v[i] >> 24) & 0xff);
+ }
+}
+static kit_bigint_t kit_bi_deserialize(uint8_t *in) {
+ ptrdiff_t i;
+ kit_bigint_t out;
+ assert(in != NULL);
+ memset(&out, 0, sizeof out);
+ for (i = 0; i < KIT_BIGINT_SIZE; i++)
+ out.v[i / 4] |= ((uint32_t) in[i]) << (8 * (i % 4));
+ return out;
+}
+static uint8_t kit_bin_digit(char hex) {
+ assert(hex == '0' || hex == '1');
+ return hex == '1' ? 1 : 0;
+}
+static kit_bigint_t kit_bi_from_bin(kit_str_t bin) {
+ kit_bigint_t z;
+ ptrdiff_t i;
+ memset(&z, 0, sizeof z);
+ for (i = 0; i < bin.size && i / 8 < KIT_BIGINT_SIZE; i++) {
+ uint8_t digit = kit_bin_digit(bin.values[bin.size - i - 1]);
+ z.v[i / 32] |= digit << (i % 32);
+ }
+ return z;
+}
+static uint8_t kit_dec_digit(char c) {
+ assert('c' >= '0' && c <= '9');
+ return c >= '0' && c <= '9' ? (uint8_t) (c - '0') : 0;
+}
+static kit_bigint_t kit_bi_from_dec(kit_str_t dec) {
+ kit_bigint_t z = kit_bi_uint32(0);
+ kit_bigint_t factor = kit_bi_uint32(1);
+ ptrdiff_t i;
+ for (i = 0; i < dec.size; i++) {
+ uint32_t digit = kit_dec_digit(dec.values[dec.size - i - 1]);
+ z = kit_bi_add(z, kit_bi_mul_uint32(factor, digit));
+ factor = kit_bi_mul_uint32(factor, 10);
+ }
+ return z;
+}
+static uint8_t kit_hex_digit(char hex) {
+ assert((hex >= '0' && hex <= '9') || (hex >= 'a' && hex <= 'f') ||
+ (hex >= 'A' && hex <= 'F'));
+ if (hex >= '0' && hex <= '9')
+ return hex - '0';
+ if (hex >= 'a' && hex <= 'f')
+ return hex - 'a';
+ if (hex >= 'A' && hex <= 'F')
+ return hex - 'A';
+ return 0;
+}
+static kit_bigint_t kit_bi_from_hex(kit_str_t hex) {
+ kit_bigint_t z;
+ ptrdiff_t i;
+ memset(&z, 0, sizeof z);
+ for (i = 0; i < hex.size && i / 2 < KIT_BIGINT_SIZE; i++) {
+ uint8_t digit = kit_hex_digit(hex.values[hex.size - i - 1]);
+ z.v[i / 8] |= digit << (4 * (i % 8));
+ }
+ return z;
+}
+static uint8_t KIT_BASE32_DIGITS[] = {
+ ['1'] = 0, ['2'] = 1, ['3'] = 2, ['4'] = 3, ['5'] = 4,
+ ['6'] = 5, ['7'] = 6, ['8'] = 7, ['9'] = 8, ['a'] = 9,
+ ['b'] = 10, ['c'] = 11, ['d'] = 12, ['e'] = 13, ['f'] = 14,
+ ['g'] = 15, ['h'] = 16, ['j'] = 17, ['k'] = 18, ['m'] = 19,
+ ['n'] = 20, ['p'] = 21, ['q'] = 22, ['r'] = 23, ['s'] = 24,
+ ['t'] = 25, ['u'] = 26, ['v'] = 27, ['w'] = 28, ['x'] = 29,
+ ['y'] = 30, ['z'] = 31
+};
+static uint8_t kit_base32_digit(char c) {
+ assert(c >= '\0' && c < sizeof KIT_BASE32_DIGITS);
+ assert(c == '1' ||
+ KIT_BASE32_DIGITS[(size_t) (unsigned char) c] != 0);
+ return c >= '\0' && c < sizeof KIT_BASE32_DIGITS
+ ? KIT_BASE32_DIGITS[(size_t) (unsigned char) c]
+ : 0;
+}
+static kit_bigint_t kit_bi_from_base32(kit_str_t base32) {
+ kit_bigint_t z;
+ ptrdiff_t i;
+ memset(&z, 0, sizeof z);
+ for (i = 0; i < base32.size; i++) {
+ z = kit_bi_shl_uint(z, 5 * i);
+ z.v[0] |= kit_base32_digit(base32.values[i]);
+ }
+ return z;
+}
+static uint8_t KIT_BASE58_DIGITS[] = {
+ ['1'] = 0, ['2'] = 1, ['3'] = 2, ['4'] = 3, ['5'] = 4,
+ ['6'] = 5, ['7'] = 6, ['8'] = 7, ['9'] = 8, ['A'] = 9,
+ ['B'] = 10, ['C'] = 11, ['D'] = 12, ['E'] = 13, ['F'] = 14,
+ ['G'] = 15, ['H'] = 16, ['J'] = 17, ['K'] = 18, ['L'] = 19,
+ ['M'] = 20, ['N'] = 21, ['P'] = 22, ['Q'] = 23, ['R'] = 24,
+ ['S'] = 25, ['T'] = 26, ['U'] = 27, ['V'] = 28, ['W'] = 29,
+ ['X'] = 30, ['Y'] = 31, ['Z'] = 32, ['a'] = 33, ['b'] = 34,
+ ['c'] = 35, ['d'] = 36, ['e'] = 37, ['f'] = 38, ['g'] = 39,
+ ['h'] = 40, ['i'] = 41, ['j'] = 42, ['k'] = 43, ['m'] = 44,
+ ['n'] = 45, ['o'] = 46, ['p'] = 47, ['q'] = 48, ['r'] = 49,
+ ['s'] = 50, ['t'] = 51, ['u'] = 52, ['v'] = 53, ['w'] = 54,
+ ['x'] = 55, ['y'] = 56, ['z'] = 57
+};
+static uint8_t kit_base58_digit(char c) {
+ assert(c >= '\0' && c < sizeof KIT_BASE58_DIGITS);
+ assert(c == '1' ||
+ KIT_BASE58_DIGITS[(size_t) (unsigned char) c] != 0);
+ return c >= '\0' && c < sizeof KIT_BASE58_DIGITS
+ ? KIT_BASE58_DIGITS[(size_t) (unsigned char) c]
+ : 0;
+}
+static kit_bigint_t kit_bi_from_base58(kit_str_t base58) {
+ kit_bigint_t z = kit_bi_uint32(0);
+ kit_bigint_t factor = kit_bi_uint32(1);
+ ptrdiff_t i;
+ for (i = 0; i < base58.size; i++) {
+ uint32_t digit = kit_base58_digit(
+ base58.values[base58.size - i - 1]);
+ z = kit_bi_add(z, kit_bi_mul_uint32(factor, digit));
+ factor = kit_bi_mul_uint32(factor, 58);
+ }
+ return z;
}
#ifdef __GNUC__
# pragma GCC pop_options
# pragma GCC diagnostic pop
#endif
-#define KIT_SZ(static_str_) \
- kit_str(sizeof(static_str_) - 1, (static_str_))
-#define KIT_WRAP_BS(string_) kit_str(strlen(string_), (string_))
-#define KIT_WRAP_STR(string_) \
- kit_str((string_).size, (string_).values)
+#define KIT_BIN(static_str_) \
+ kit_bi_from_bin(kit_str(sizeof(static_str_) - 1, (static_str_)))
+#define KIT_DEC(static_str_) \
+ kit_bi_from_dec(kit_str(sizeof(static_str_) - 1, (static_str_)))
+#define KIT_HEX(static_str_) \
+ kit_bi_from_hex(kit_str(sizeof(static_str_) - 1, (static_str_)))
+#define KIT_BASE32(static_str_) \
+ kit_bi_from_base32(kit_str(sizeof(static_str_) - 1, (static_str_)))
+#define KIT_BASE58(static_str_) \
+ kit_bi_from_base58(kit_str(sizeof(static_str_) - 1, (static_str_)))
#ifndef KIT_DISABLE_SHORT_NAMES
-# define BS(string_) kit_make_bs(KIT_WRAP_STR(string_))
-# define string_mut_t kit_string_mut_t
-# define string_ref_t kit_string_ref_t
-# define out_str_t kit_out_str_t
-# define str_t kit_str_t
-# define SZ KIT_SZ
-# define WRAP_BS KIT_WRAP_BS
-# define WRAP_STR KIT_WRAP_STR
+# define bigint_t kit_bigint_t
+# define bi_uint32 kit_bi_uint32
+# define bi_uint64 kit_bi_uint64
+# define bi_int32 kit_bi_int32
+# define bi_int64 kit_bi_int64
+# define bi_is_zero kit_bi_is_zero
+# define bi_is_neg kit_bi_is_neg
+# define bi_equal kit_bi_equal
+# define bi_compare kit_bi_compare
+# define bi_carry kit_bi_carry
+# define bi_inc kit_bi_inc
+# define bi_dec kit_bi_dec
+# define bi_add kit_bi_add
+# define bi_neg kit_bi_neg
+# define bi_sub kit_bi_sub
+# define bi_mul kit_bi_mul
+# define bi_div kit_bi_div
+# define bi_serialize kit_bi_serialize
+# define bi_deserialize kit_bi_deserialize
+# define BIN KIT_BIN
+# define DEC KIT_DEC
+# define HEX KIT_HEX
+# define BASE32 KIT_BASE32
+# define BASE58 KIT_BASE58
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/input_stream.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_INPUT_STREAM_H
+#define KIT_INPUT_STREAM_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef ptrdiff_t (*kit_is_read_fn)(void *state,
+ kit_str_t destination);
+typedef struct {
+ void *state;
+ kit_is_read_fn read;
+} kit_is_handle_t;
+kit_is_handle_t kit_is_wrap_string(kit_str_t string,
+ kit_allocator_t alloc);
+void kit_is_destroy(kit_is_handle_t in);
+#define KIT_IS_WRAP_STRING(string) \
+ kit_is_wrap_string((string), kit_alloc_default())
+#define KIT_IS_READ(in, destination) \
+ (in).read((in).state, (destination))
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define is_read_fn kit_is_read_fn
+# define is_handle_t kit_is_handle_t
+# define is_wrap_string kit_is_wrap_string
+# define is_destroy kit_is_destroy
+# define IS_WRAP_STRING KIT_IS_WRAP_STRING
+# define IS_READ KIT_IS_READ
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/input_buffer.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_INPUT_BUFFER_H
+#define KIT_INPUT_BUFFER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef struct {
+ kit_status_t status;
+ ptrdiff_t offset;
+ void *internal;
+ kit_string_t data;
+} kit_ib_handle_t;
+kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream,
+ kit_allocator_t alloc);
+kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, ptrdiff_t size);
+typedef int (*kit_ib_read_condition_fn)(kit_str_t data);
+kit_ib_handle_t kit_ib_read_while(kit_ib_handle_t buf,
+ kit_ib_read_condition_fn condition);
+void kit_ib_destroy(kit_ib_handle_t buf);
+#define KIT_IB_WRAP(upstream) \
+ kit_ib_wrap(upstream, kit_alloc_default())
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define ib_handle_t kit_ib_handle_t
+# define ib_read_condition_fn kit_ib_read_condition_fn
+# define ib_wrap kit_ib_wrap
+# define ib_read kit_ib_read
+# define ib_read_while kit_ib_read_while
+# define ib_destroy kit_ib_destroy
+# define IB_WRAP KIT_IB_WRAP
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/async_function.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_ASYNC_FUNCTION_H
+#define KIT_ASYNC_FUNCTION_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <stddef.h>
+#include <string.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-function"
+# pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#endif
+typedef struct {
+ int _;
+} kit_af_void;
+typedef void (*kit_af_state_machine)(void *self_void_);
+#define KIT_AF_STATE_DATA \
+ struct { \
+ int _index; \
+ ptrdiff_t _id; \
+ kit_af_state_machine _state_machine; \
+ }
+typedef struct {
+ KIT_AF_STATE_DATA;
+} kit_af_type_void;
+#define KIT_AF_INTERNAL(coro_) (*((kit_af_type_void *) (coro_)))
+#ifdef KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH
+/* Application should implement this function if custom async
+ * function dispatch is enabled.
+ *
+ * See KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH macro.
+ */
+void kit_async_function_dispatch(void *promise);
+#else
+static void kit_async_function_dispatch(void *promise) {
+ /* Dynamic dispatch by default.
+ */
+ KIT_AF_INTERNAL(promise)._state_machine(promise);
+}
+#endif
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+#define KIT_AF_STATE(ret_type_, name_, ...) \
+ struct name_##_coro_state_ { \
+ KIT_AF_STATE_DATA; \
+ ret_type_ return_value; \
+ __VA_ARGS__ \
+ }
+#define KIT_AF_DECL(name_) void name_(void *self_void_)
+#define KIT_CORO_IMPL(name_) \
+ KIT_AF_DECL(name_) { \
+ struct name_##_coro_state_ *self = \
+ (struct name_##_coro_state_ *) self_void_; \
+ switch (self->_index) { \
+ case 0:;
+#define KIT_AF_LINE_() __LINE__
+#define KIT_CORO_END \
+ } \
+ self->_index = -1; \
+ }
+#define KIT_CORO_DECL(ret_type_, name_, ...) \
+ KIT_AF_STATE(ret_type_, name_, __VA_ARGS__); \
+ KIT_AF_DECL(name_)
+#define KIT_CORO(ret_type_, name_, ...) \
+ KIT_AF_STATE(ret_type_, name_, __VA_ARGS__); \
+ KIT_CORO_IMPL(name_)
+#define KIT_CORO_DECL_VOID(name_, ...) \
+ KIT_CORO_DECL(kit_af_void, name_, __VA_ARGS__)
+#define KIT_CORO_VOID(name_, ...) \
+ KIT_CORO(kit_af_void, name_, __VA_ARGS__)
+#define KIT_STATIC_CORO(ret_type_, name_, ...) \
+ KIT_AF_STATE(ret_type_, name_, __VA_ARGS__); \
+ static KIT_CORO_IMPL(name_)
+#define KIT_STATIC_CORO_VOID(name_, ...) \
+ KIT_STATIC_CORO(kit_af_void, name_, __VA_ARGS__)
+#define KIT_AF_EXECUTE(promise_) \
+ kit_async_function_dispatch(&(promise_))
+#define KIT_AF_NEXT(promise_) \
+ (kit_async_function_dispatch(&(promise_)), (promise_).return_value)
+#define KIT_AF_YIELD(...) \
+ do { \
+ self->_index = KIT_AF_LINE_(); \
+ self->return_value = __VA_ARGS__; \
+ return; \
+ case KIT_AF_LINE_():; \
+ } while (0)
+#define KIT_AF_YIELD_VOID \
+ do { \
+ self->_index = KIT_AF_LINE_(); \
+ return; \
+ case KIT_AF_LINE_():; \
+ } while (0)
+#define KIT_AF_RETURN(...) \
+ do { \
+ self->_index = -1; \
+ self->return_value = __VA_ARGS__; \
+ return; \
+ } while (0)
+#define KIT_AF_RETURN_VOID \
+ do { \
+ self->_index = -1; \
+ return; \
+ } while (0)
+#define KIT_AF_AWAIT(promise_) \
+ do { \
+ case KIT_AF_LINE_(): \
+ if ((promise_)._index != -1) { \
+ self->_index = KIT_AF_LINE_(); \
+ kit_async_function_dispatch(&(promise_)); \
+ } \
+ if ((promise_)._index != -1) \
+ return; \
+ } while (0)
+#define KIT_AF_YIELD_AWAIT(promise_) \
+ do { \
+ case KIT_AF_LINE_(): \
+ if ((promise_)._index != -1) { \
+ self->_index = KIT_AF_LINE_(); \
+ kit_async_function_dispatch(&(promise_)); \
+ self->return_value = (promise_).return_value; \
+ return; \
+ } \
+ } while (0)
+#define KIT_AF_TYPE(coro_) struct coro_##_coro_state_
+#define KIT_AF_INITIAL(id_, coro_) \
+ ._index = 0, ._id = (id_), ._state_machine = (coro_)
+#define KIT_AF_CREATE(promise_, coro_, ...) \
+ KIT_AF_TYPE(coro_) \
+ promise_ = { KIT_AF_INITIAL(0, coro_), __VA_ARGS__ }
+#define KIT_AF_CREATE_ID(promise_, id_, ...) \
+ KIT_AF_TYPE(coro_) \
+ promise_ = { KIT_AF_INITIAL(id_, NULL), __VA_ARGS__ }
+#define KIT_AF_INIT(promise_, coro_, ...) \
+ do { \
+ KIT_AF_CREATE(kit_af_temp_, coro_, __VA_ARGS__); \
+ memcpy(&(promise_), &kit_af_temp_, sizeof kit_af_temp_); \
+ } while (0)
+#define KIT_AF_INIT_ID(promise_, id_, ...) \
+ do { \
+ KIT_AF_CREATE_ID(kit_af_temp_, id_, __VA_ARGS__); \
+ memcpy(&(promise_), &kit_af_temp_, sizeof kit_af_temp_); \
+ } while (0)
+#define KIT_AF_FINISHED(promise_) ((promise_)._index == -1)
+#define KIT_AF_FINISHED_N(return_, promises_, size_) \
+ do { \
+ int kit_af_index_; \
+ (return_) = 1; \
+ for (kit_af_index_ = 0; kit_af_index_ < (size_); \
+ kit_af_index_++) \
+ if (!KIT_AF_FINISHED((promises_)[kit_af_index_])) { \
+ (return_) = 0; \
+ break; \
+ } \
+ } while (0)
+#define KIT_AF_FINISHED_ALL(return_, promises_) \
+ KIT_AF_FINISHED_N((return_), (promises_), \
+ sizeof(promises_) / sizeof((promises_)[0]))
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define af_void kit_af_void
+# define af_state_machine kit_af_state_machine
+# define af_type_void kit_af_type_void
+# define AF_STATE_DATA KIT_AF_STATE_DATA
+# define AF_STATE KIT_AF_STATE
+# define AF_DECL KIT_AF_DECL
+# define CORO_IMPL KIT_CORO_IMPL
+# define CORO_END KIT_CORO_END
+# define CORO_DECL KIT_CORO_DECL
+# define CORO KIT_CORO
+# define CORO_DECL_VOID KIT_CORO_DECL_VOID
+# define STATIC_CORO KIT_STATIC_CORO
+# define STATIC_CORO_VOID KIT_STATIC_CORO_VOID
+# define CORO_VOID KIT_CORO_VOID
+# define AF_EXECUTE KIT_AF_EXECUTE
+# define AF_NEXT KIT_AF_NEXT
+# define AF_YIELD KIT_AF_YIELD
+# define AF_YIELD_VOID KIT_AF_YIELD_VOID
+# define AF_RETURN KIT_AF_RETURN
+# define AF_RETURN_VOID KIT_AF_RETURN_VOID
+# define AF_AWAIT KIT_AF_AWAIT
+# define AF_YIELD_AWAIT KIT_AF_YIELD_AWAIT
+# define AF_TYPE KIT_AF_TYPE
+# define AF_INITIAL KIT_AF_INITIAL
+# define AF_CREATE KIT_AF_CREATE
+# define AF_INIT KIT_AF_INIT
+# define AF_FINISHED KIT_AF_FINISHED
+# define AF_FINISHED_N KIT_AF_FINISHED_N
+# define AF_FINISHED_ALL KIT_AF_FINISHED_ALL
#endif
#ifdef __cplusplus
}
@@ -297,7 +1491,7 @@ static char const *kit_make_bs(kit_str_t const s) {
#endif
/*********************************************************************
* *
- * File: ./source/kit/file.h *
+ * File: source/kit/file.h *
* *
*********************************************************************/
#ifndef KIT_FILE_H
@@ -314,11 +1508,6 @@ extern "C" {
# define KIT_PATH_DELIM "/"
# define KIT_ENV_HOME "HOME"
#endif
-typedef enum {
- KIT_PATH_NONE,
- KIT_PATH_FILE,
- KIT_PATH_FOLDER
-} kit_path_type_t;
kit_string_t kit_path_norm(kit_str_t path, kit_allocator_t alloc);
kit_string_t kit_path_join(kit_str_t left, kit_str_t right,
kit_allocator_t alloc);
@@ -332,6 +1521,11 @@ kit_status_t kit_file_remove(kit_str_t path);
kit_status_t kit_file_remove_folder(kit_str_t path);
kit_status_t kit_file_remove_recursive(kit_str_t path,
kit_allocator_t alloc);
+typedef enum {
+ KIT_PATH_NONE,
+ KIT_PATH_FILE,
+ KIT_PATH_FOLDER
+} kit_path_type_t;
kit_path_type_t kit_path_type(kit_str_t path);
typedef struct {
kit_status_t status;
@@ -360,10 +1554,10 @@ void kit_path_list_destroy(kit_path_list_t list);
# define file_remove kit_file_remove
# define file_remove_folder kit_file_remove_folder
# define file_remove_recursive kit_file_remove_recursive
-# define path_type kit_path_type
-# define file_size_result_t kit_file_size_result_t
-# define file_size kit_file_size
# define path_type_t kit_path_type_t
+# define path_type kit_path_type
+# define file_info_t kit_file_info_t
+# define file_info kit_file_info
# define path_list_t kit_path_list_t
# define file_enum_folder kit_file_enum_folder
# define path_list_destroy kit_path_list_destroy
@@ -380,7 +1574,195 @@ void kit_path_list_destroy(kit_path_list_t list);
#endif
/*********************************************************************
* *
- * File: ./source/kit/allocator.c *
+ * File: source/kit/mersenne_twister_64.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_MERSENNE_TWISTER_64_H
+#define KIT_MERSENNE_TWISTER_64_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <stddef.h>
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+enum {
+ KIT_MT64_N = 312,
+};
+typedef struct {
+ uint64_t mt[KIT_MT64_N];
+ uint64_t index;
+} kit_mt64_state_t;
+void kit_mt64_init_array(kit_mt64_state_t *state, ptrdiff_t size,
+ uint64_t *seed);
+void kit_mt64_init(kit_mt64_state_t *state, uint64_t seed);
+void kit_mt64_rotate(kit_mt64_state_t *state);
+uint64_t kit_mt64_generate(kit_mt64_state_t *state);
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define mt64_state_t kit_mt64_state_t
+# define mt64_init_array kit_mt64_init_array
+# define mt64_init kit_mt64_init
+# define mt64_rotate kit_mt64_rotate
+# define mt64_generate kit_mt64_generate
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/secure_random.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_SECURE_RANDOM_H
+#define KIT_SECURE_RANDOM_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <stddef.h>
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+void kit_secure_random(ptrdiff_t size, void *data);
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define secure_random kit_secure_random
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/sha256.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_SHA256_H
+#define KIT_SHA256_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <stddef.h>
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+enum { KIT_SHA256_BLOCK_SIZE = 32 };
+typedef struct {
+ uint8_t v[KIT_SHA256_BLOCK_SIZE];
+} kit_sha256_hash_t;
+kit_sha256_hash_t kit_sha256(ptrdiff_t size, uint8_t *data);
+#ifdef __cplusplus
+}
+#endif
+#ifndef KIT_DISABLE_SHORT_NAMES
+# define SHA256_BLOCK_SIZE KIT_SHA256_BLOCK_SIZE
+# define sha256_hash_t kit_sha256_hash_t
+# define sha256 kit_sha256
+#endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/sockets.h *
+ * *
+ *********************************************************************/
+#ifndef KIT_SOCKETS_H
+#define KIT_SOCKETS_H
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#ifndef KIT_DISABLE_SYSTEM_SOCKETS
+# ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-function"
+# pragma GCC diagnostic ignored "-Wunknown-pragmas"
+# endif
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define WIN32_LEAN_AND_MEAN
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define socket_t SOCKET
+# define socklen_t int
+# ifdef __cplusplus
+extern "C" {
+# endif
+static kit_status_t kit_sockets_init(void) {
+ WSADATA data;
+ memset(&data, 0, sizeof data);
+ WORD version = MAKEWORD(2, 2);
+ return WSAStartup(version, &data) == ERROR_SUCCESS
+ ? KIT_OK
+ : KIT_ERROR_SOCKETS_STARTUP_FAILED;
+}
+static kit_status_t kit_sockets_cleanup(void) {
+ WSACleanup();
+ return KIT_OK;
+}
+static int kit_socket_set_blocking(socket_t s) {
+ u_long flag = 0;
+ return ioctlsocket(s, FIONBIO, &flag) == 0
+ ? KIT_OK
+ : KIT_ERROR_SOCKET_CONTROL_FAILED;
+}
+static int kit_socket_set_nonblocking(socket_t s) {
+ u_long flag = 1;
+ return ioctlsocket(s, FIONBIO, &flag) == 0
+ ? KIT_OK
+ : KIT_ERROR_SOCKET_CONTROL_FAILED;
+}
+# ifdef __cplusplus
+}
+# endif
+# else
+# include <arpa/inet.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <netinet/in.h>
+# include <signal.h>
+# include <sys/ioctl.h>
+# include <sys/select.h>
+# include <sys/socket.h>
+# include <sys/types.h>
+# include <unistd.h>
+# define socket_t int
+# define closesocket close
+# define INVALID_SOCKET -1
+# ifdef __cplusplus
+extern "C" {
+# endif
+static kit_status_t kit_sockets_init(void) {
+ signal(SIGPIPE, SIG_IGN);
+ return KIT_OK;
+}
+static kit_status_t kit_sockets_cleanup(void) {
+ return KIT_OK;
+}
+static int kit_socket_set_blocking(socket_t s) {
+ int const flags = fcntl(s, F_GETFL, 0);
+ return fcntl(s, F_SETFL, flags & ~O_NONBLOCK) == 0
+ ? KIT_OK
+ : KIT_ERROR_SOCKET_CONTROL_FAILED;
+}
+static int kit_socket_set_nonblocking(socket_t s) {
+ int const flags = fcntl(s, F_GETFL, 0);
+ return fcntl(s, F_SETFL, flags | O_NONBLOCK) == 0
+ ? KIT_OK
+ : KIT_ERROR_SOCKET_CONTROL_FAILED;
+}
+# ifdef __cplusplus
+}
+# endif
+# endif
+# ifdef __GNUC__
+# pragma GCC diagnostic pop
+# endif
+#endif
+#endif
+#ifdef KIT_IMPLEMENTATION
+/*********************************************************************
+ * *
+ * File: source/kit/allocator.c *
* *
*********************************************************************/
#include <assert.h>
@@ -430,52 +1812,744 @@ kit_allocator_t kit_alloc_default(void) {
}
/*********************************************************************
* *
- * File: ./source/kit/array_ref.c *
+ * File: source/kit/thread.posix.c *
* *
*********************************************************************/
-#include <string.h>
-int kit_ar_equal_bytes(ptrdiff_t left_element_size,
- ptrdiff_t left_size, void const *left_data,
- ptrdiff_t right_element_size,
- ptrdiff_t right_size, void const *right_data) {
- ptrdiff_t i;
- if (left_element_size != right_element_size)
- return 0;
- if (left_size != right_size)
- return 0;
- for (i = 0; i < left_size; i++)
- if (memcmp((char const *) left_data + i * left_element_size,
- (char const *) right_data + i * left_element_size,
- left_element_size) != 0)
- return 0;
- return 1;
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+# if !defined(_WIN32) || defined(__CYGWIN__)
+# include <assert.h>
+# include <errno.h>
+# include <limits.h>
+# include <sched.h>
+# include <stdint.h> /* intptr_t */
+# include <stdlib.h>
+# include <unistd.h>
+# ifndef PTHREAD_STACK_MIN
+# define PTHREAD_STACK_MIN 16384
+# endif
+/*
+Configuration macro:
+ EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+ Use pthread_mutex_timedlock() for `mtx_timedlock()'
+ Otherwise use mtx_trylock() + *busy loop* emulation.
+*/
+# if !defined(__CYGWIN__) && !defined(__APPLE__) && \
+ !defined(__NetBSD__)
+# define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+# endif
+/*
+Implementation limits:
+ - Conditionally emulation for "mutex with timeout"
+ (see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro)
+*/
+typedef struct {
+ thrd_start_t func;
+ void *arg;
+ kit_allocator_t alloc;
+} impl_thrd_param_t;
+static void *impl_thrd_routine(void *p) {
+ impl_thrd_param_t pack = *((impl_thrd_param_t *) p);
+ kit_alloc_dispatch(pack.alloc, KIT_DEALLOCATE, 0, 0, p);
+ return (void *) (intptr_t) pack.func(pack.arg);
}
-int kit_ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size,
- void const *left_data,
- ptrdiff_t right_element_size, ptrdiff_t right_size,
- void const *right_data,
- kit_ar_compare_fn compare) {
- ptrdiff_t i;
- if (left_element_size < right_element_size)
- return -1;
- if (left_element_size > right_element_size)
- return 1;
- for (i = 0; i < left_size && i < right_size; i++) {
- int const c = compare(
- (char const *) left_data + i * left_element_size,
- (char const *) right_data + i * left_element_size);
- if (c != 0)
- return c;
- }
- if (left_size < right_size)
- return -1;
- if (left_size > right_size)
+void call_once(once_flag *flag, void (*func)(void)) {
+ pthread_once(flag, func);
+}
+int cnd_broadcast(cnd_t *cond) {
+ assert(cond != NULL);
+ return (pthread_cond_broadcast(cond) == 0) ? thrd_success
+ : thrd_error;
+}
+void cnd_destroy(cnd_t *cond) {
+ assert(cond);
+ pthread_cond_destroy(cond);
+}
+int cnd_init(cnd_t *cond) {
+ assert(cond != NULL);
+ return (pthread_cond_init(cond, NULL) == 0) ? thrd_success
+ : thrd_error;
+}
+int cnd_signal(cnd_t *cond) {
+ assert(cond != NULL);
+ return (pthread_cond_signal(cond) == 0) ? thrd_success : thrd_error;
+}
+int cnd_timedwait(cnd_t *cond, mtx_t *mtx,
+ struct timespec const *abs_time) {
+ int rt;
+ assert(mtx != NULL);
+ assert(cond != NULL);
+ assert(abs_time != NULL);
+ rt = pthread_cond_timedwait(cond, mtx, abs_time);
+ if (rt == ETIMEDOUT)
+ return thrd_timedout;
+ return (rt == 0) ? thrd_success : thrd_error;
+}
+int cnd_wait(cnd_t *cond, mtx_t *mtx) {
+ assert(mtx != NULL);
+ assert(cond != NULL);
+ return (pthread_cond_wait(cond, mtx) == 0) ? thrd_success
+ : thrd_error;
+}
+void mtx_destroy(mtx_t *mtx) {
+ assert(mtx != NULL);
+ pthread_mutex_destroy(mtx);
+}
+/*
+ * XXX: Workaround when building with -O0 and without pthreads link.
+ *
+ * In such cases constant folding and dead code elimination won't be
+ * available, thus the compiler will always add the pthread_mutexattr*
+ * functions into the binary. As we try to link, we'll fail as the
+ * symbols are unresolved.
+ *
+ * Ideally we'll enable the optimisations locally, yet that does not
+ * seem to work.
+ *
+ * So the alternative workaround is to annotate the symbols as weak.
+ * Thus the linker will be happy and things don't clash when building
+ * with -O1 or greater.
+ */
+# if defined(KIT_HAVE_FUNC_ATTRIBUTE_WEAK) && !defined(__CYGWIN__)
+__attribute__((weak)) int pthread_mutexattr_init(
+ pthread_mutexattr_t *attr);
+__attribute__((weak)) int pthread_mutexattr_settype(
+ pthread_mutexattr_t *attr, int type);
+__attribute__((weak)) int pthread_mutexattr_destroy(
+ pthread_mutexattr_t *attr);
+# endif
+int mtx_init(mtx_t *mtx, int type) {
+# ifdef KIT_HAVE_PTHREAD_MUTEXATTR_SETTYPE
+ pthread_mutexattr_t attr;
+# endif
+ assert(mtx != NULL);
+ if (type != mtx_plain && type != mtx_timed &&
+ type != (mtx_plain | mtx_recursive) &&
+ type != (mtx_timed | mtx_recursive))
+ return thrd_error;
+ if ((type & mtx_recursive) == 0) {
+ pthread_mutex_init(mtx, NULL);
+ return thrd_success;
+ }
+# ifdef KIT_HAVE_PTHREAD_MUTEXATTR_SETTYPE
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(mtx, &attr);
+ pthread_mutexattr_destroy(&attr);
+ return thrd_success;
+# else
+ return thrd_error;
+# endif
+}
+int mtx_lock(mtx_t *mtx) {
+ assert(mtx != NULL);
+ return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error;
+}
+int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) {
+ assert(mtx != NULL);
+ assert(ts != NULL);
+ {
+# ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+ int rt;
+ rt = pthread_mutex_timedlock(mtx, ts);
+ if (rt == 0)
+ return thrd_success;
+ return (rt == ETIMEDOUT) ? thrd_timedout : thrd_error;
+# else
+ time_t expire = time(NULL);
+ expire += ts->tv_sec;
+ while (mtx_trylock(mtx) != thrd_success) {
+ time_t now = time(NULL);
+ if (expire < now)
+ return thrd_timedout;
+ // busy loop!
+ thrd_yield();
+ }
+ return thrd_success;
+# endif
+ }
+}
+int mtx_trylock(mtx_t *mtx) {
+ assert(mtx != NULL);
+ return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
+}
+int mtx_unlock(mtx_t *mtx) {
+ assert(mtx != NULL);
+ return (pthread_mutex_unlock(mtx) == 0) ? thrd_success : thrd_error;
+}
+int thrd_create_with_stack(thrd_t *thr, thrd_start_t func, void *arg,
+ ptrdiff_t const require_stack_size) {
+ impl_thrd_param_t *pack;
+ assert(thr != NULL);
+ assert(require_stack_size == 0 ||
+ require_stack_size >= PTHREAD_STACK_MIN);
+ pthread_attr_t attr;
+ pthread_attr_t *attr_p = NULL;
+ if (require_stack_size > 0) {
+ ptrdiff_t const page_size = (ptrdiff_t) sysconf(_SC_PAGESIZE);
+ ptrdiff_t const delta = require_stack_size % page_size;
+ ptrdiff_t const stack_size = delta == 0 ? require_stack_size
+ : require_stack_size +
+ page_size - delta;
+ if (pthread_attr_init(&attr) != 0)
+ return thrd_nomem;
+ if (pthread_attr_setstacksize(&attr, (size_t) stack_size) != 0)
+ return thrd_wrong_stack_size;
+ attr_p = &attr;
+ }
+ kit_allocator_t alloc = kit_alloc_default();
+ pack = (impl_thrd_param_t *) kit_alloc_dispatch(
+ alloc, KIT_ALLOCATE, sizeof(impl_thrd_param_t), 0, NULL);
+ if (!pack) {
+ if (attr_p)
+ pthread_attr_destroy(attr_p);
+ return thrd_nomem;
+ }
+ pack->func = func;
+ pack->arg = arg;
+ pack->alloc = alloc;
+ if (pthread_create(thr, attr_p, impl_thrd_routine, pack) != 0) {
+ kit_alloc_dispatch(alloc, KIT_DEALLOCATE, 0, 0, pack);
+ if (attr_p)
+ pthread_attr_destroy(attr_p);
+ return thrd_error;
+ }
+ if (attr_p)
+ pthread_attr_destroy(attr_p);
+ return thrd_success;
+}
+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) {
+ return thrd_create_with_stack(thr, func, arg, 0);
+}
+thrd_t thrd_current(void) {
+ return pthread_self();
+}
+int thrd_detach(thrd_t thr) {
+ return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;
+}
+int thrd_equal(thrd_t thr0, thrd_t thr1) {
+ return pthread_equal(thr0, thr1);
+}
+_Noreturn void thrd_exit(int res) {
+ pthread_exit((void *) (intptr_t) res);
+}
+int thrd_join(thrd_t thr, int *res) {
+ void *code;
+ if (pthread_join(thr, &code) != 0)
+ return thrd_error;
+ if (res)
+ *res = (int) (intptr_t) code;
+ return thrd_success;
+}
+int thrd_sleep(const struct timespec *time_point,
+ struct timespec *remaining) {
+ assert(time_point != NULL);
+ return nanosleep(time_point, remaining);
+}
+void thrd_yield(void) {
+ sched_yield();
+}
+# endif
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/thread.win32.c *
+ * *
+ *********************************************************************/
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# include <assert.h>
+# include <errno.h>
+# include <limits.h>
+# include <process.h>
+# include <stdbool.h>
+# include <stdlib.h>
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# include <Windows.h>
+/*
+Configuration macro:
+ EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+ Use native WindowsAPI one-time initialization function.
+ (requires WinVista or later)
+ Otherwise emulate by mtx_trylock() + *busy loop* for WinXP.
+ EMULATED_THREADS_TSS_DTOR_SLOTNUM
+ Max registerable TSS dtor number.
+*/
+# if _WIN32_WINNT >= 0x0600
+/* Prefer native WindowsAPI on newer environment. */
+# if !defined(__MINGW32__)
+# define EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+# endif
+# endif
+# define EMULATED_THREADS_TSS_DTOR_SLOTNUM \
+ 64 /* see TLS_MINIMUM_AVAILABLE */
+/* check configuration */
+# if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && \
+ (_WIN32_WINNT < 0x0600)
+# error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600
+# endif
+static_assert(sizeof(cnd_t) == sizeof(CONDITION_VARIABLE),
+ "The size of cnd_t must equal to CONDITION_VARIABLE");
+static_assert(sizeof(thrd_t) == sizeof(HANDLE),
+ "The size of thrd_t must equal to HANDLE");
+static_assert(sizeof(tss_t) == sizeof(DWORD),
+ "The size of tss_t must equal to DWORD");
+static_assert(sizeof(mtx_t) == sizeof(CRITICAL_SECTION),
+ "The size of mtx_t must equal to CRITICAL_SECTION");
+static_assert(sizeof(once_flag) == sizeof(INIT_ONCE),
+ "The size of once_flag must equal to INIT_ONCE");
+/*
+Implementation limits:
+ - Conditionally emulation for "Initialization functions"
+ (see EMULATED_THREADS_USE_NATIVE_CALL_ONCE macro)
+ - Emulated `mtx_timelock()' with mtx_trylock() + *busy loop*
+*/
+typedef struct {
+ thrd_start_t func;
+ void *arg;
+ thrd_t thrd;
+ kit_allocator_t alloc;
+} impl_thrd_param_t;
+struct thrd_state {
+ thrd_t thrd;
+ bool handle_need_close;
+};
+static thread_local struct thrd_state impl_current_thread = { 0 };
+static unsigned __stdcall impl_thrd_routine(void *p) {
+ impl_thrd_param_t *pack_p = (impl_thrd_param_t *) p;
+ impl_thrd_param_t pack;
+ int code;
+ impl_current_thread.thrd = pack_p->thrd;
+ impl_current_thread.handle_need_close = false;
+ memcpy(&pack, pack_p, sizeof(impl_thrd_param_t));
+ kit_alloc_dispatch(pack.alloc, KIT_DEALLOCATE, 0, 0, p);
+ code = pack.func(pack.arg);
+ return (unsigned) code;
+}
+static time_t impl_timespec2msec(const struct timespec *ts) {
+ return (ts->tv_sec * 1000U) + (ts->tv_nsec / 1000000L);
+}
+static DWORD impl_abs2relmsec(const struct timespec *abs_time) {
+ const time_t abs_ms = impl_timespec2msec(abs_time);
+ struct timespec now;
+ timespec_get(&now, TIME_UTC);
+ const time_t now_ms = impl_timespec2msec(&now);
+ const DWORD rel_ms = (abs_ms > now_ms) ? (DWORD) (abs_ms - now_ms)
+ : 0;
+ return rel_ms;
+}
+# ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+struct impl_call_once_param {
+ void (*func)(void);
+};
+static BOOL CALLBACK impl_call_once_callback(PINIT_ONCE InitOnce,
+ PVOID Parameter,
+ PVOID *Context) {
+ struct impl_call_once_param *param = (struct impl_call_once_param *)
+ Parameter;
+ (param->func)();
+ ((void) InitOnce);
+ ((void) Context); /* suppress warning */
+ return TRUE;
+}
+# endif /* ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE */
+static struct impl_tss_dtor_entry {
+ tss_t key;
+ tss_dtor_t dtor;
+} impl_tss_dtor_tbl[EMULATED_THREADS_TSS_DTOR_SLOTNUM];
+static int impl_tss_dtor_register(tss_t key, tss_dtor_t dtor) {
+ int i;
+ for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
+ if (!impl_tss_dtor_tbl[i].dtor)
+ break;
+ }
+ if (i == EMULATED_THREADS_TSS_DTOR_SLOTNUM)
return 1;
+ impl_tss_dtor_tbl[i].key = key;
+ impl_tss_dtor_tbl[i].dtor = dtor;
return 0;
}
+static void impl_tss_dtor_invoke(void) {
+ int i;
+ for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
+ if (impl_tss_dtor_tbl[i].dtor) {
+ void *val = (void *) (size_t) tss_get(impl_tss_dtor_tbl[i].key);
+ if (val)
+ (impl_tss_dtor_tbl[i].dtor)(val);
+ }
+ }
+}
+void call_once(once_flag *flag, void (*func)(void)) {
+ assert(flag && func);
+# ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+ {
+ struct impl_call_once_param param;
+ param.func = func;
+ InitOnceExecuteOnce((PINIT_ONCE) flag, impl_call_once_callback,
+ (PVOID) &param, NULL);
+ }
+# else
+ if (InterlockedCompareExchangePointer(
+ (PVOID volatile *) &flag->status, (PVOID) 1, (PVOID) 0) ==
+ 0) {
+ (func)();
+ InterlockedExchangePointer((PVOID volatile *) &flag->status,
+ (PVOID) 2);
+ } else {
+ while (flag->status == 1) {
+ // busy loop!
+ thrd_yield();
+ }
+ }
+# endif
+}
+int cnd_broadcast(cnd_t *cond) {
+ assert(cond != NULL);
+ WakeAllConditionVariable((PCONDITION_VARIABLE) cond);
+ return thrd_success;
+}
+void cnd_destroy(cnd_t *cond) {
+ assert(cond != NULL);
+ /* do nothing */
+ (void) cond;
+}
+int cnd_init(cnd_t *cond) {
+ assert(cond != NULL);
+ InitializeConditionVariable((PCONDITION_VARIABLE) cond);
+ return thrd_success;
+}
+int cnd_signal(cnd_t *cond) {
+ assert(cond != NULL);
+ WakeConditionVariable((PCONDITION_VARIABLE) cond);
+ return thrd_success;
+}
+int cnd_timedwait(cnd_t *cond, mtx_t *mtx,
+ const struct timespec *abs_time) {
+ assert(cond != NULL);
+ assert(mtx != NULL);
+ assert(abs_time != NULL);
+ const DWORD timeout = impl_abs2relmsec(abs_time);
+ if (SleepConditionVariableCS((PCONDITION_VARIABLE) cond,
+ (PCRITICAL_SECTION) mtx, timeout))
+ return thrd_success;
+ return (GetLastError() == ERROR_TIMEOUT) ? thrd_timedout
+ : thrd_error;
+}
+int cnd_wait(cnd_t *cond, mtx_t *mtx) {
+ assert(cond != NULL);
+ assert(mtx != NULL);
+ SleepConditionVariableCS((PCONDITION_VARIABLE) cond,
+ (PCRITICAL_SECTION) mtx, INFINITE);
+ return thrd_success;
+}
+void mtx_destroy(mtx_t *mtx) {
+ assert(mtx);
+ DeleteCriticalSection((PCRITICAL_SECTION) mtx);
+}
+int mtx_init(mtx_t *mtx, int type) {
+ assert(mtx != NULL);
+ if (type != mtx_plain && type != mtx_timed &&
+ type != (mtx_plain | mtx_recursive) &&
+ type != (mtx_timed | mtx_recursive))
+ return thrd_error;
+ InitializeCriticalSection((PCRITICAL_SECTION) mtx);
+ return thrd_success;
+}
+int mtx_lock(mtx_t *mtx) {
+ assert(mtx != NULL);
+ EnterCriticalSection((PCRITICAL_SECTION) mtx);
+ return thrd_success;
+}
+int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) {
+ assert(mtx != NULL);
+ assert(ts != NULL);
+ while (mtx_trylock(mtx) != thrd_success) {
+ if (impl_abs2relmsec(ts) == 0)
+ return thrd_timedout;
+ /* busy loop! */
+ thrd_yield();
+ }
+ return thrd_success;
+}
+int mtx_trylock(mtx_t *mtx) {
+ assert(mtx != NULL);
+ return TryEnterCriticalSection((PCRITICAL_SECTION) mtx)
+ ? thrd_success
+ : thrd_busy;
+}
+int mtx_unlock(mtx_t *mtx) {
+ assert(mtx != NULL);
+ LeaveCriticalSection((PCRITICAL_SECTION) mtx);
+ return thrd_success;
+}
+int thrd_create_with_stack(thrd_t *thr, thrd_start_t func, void *arg,
+ ptrdiff_t const stack_size) {
+ impl_thrd_param_t *pack;
+ uintptr_t handle;
+ assert(thr != NULL);
+ assert(stack_size >= 0 && stack_size < 0x100000000);
+ kit_allocator_t alloc = kit_alloc_default();
+ pack = (impl_thrd_param_t *) kit_alloc_dispatch(
+ alloc, KIT_ALLOCATE, (sizeof(impl_thrd_param_t)), 0, NULL);
+ if (!pack)
+ return thrd_nomem;
+ pack->func = func;
+ pack->arg = arg;
+ pack->alloc = alloc;
+ handle = _beginthreadex(NULL, (unsigned) stack_size,
+ impl_thrd_routine, pack, CREATE_SUSPENDED,
+ NULL);
+ if (handle == 0) {
+ kit_alloc_dispatch(alloc, KIT_DEALLOCATE, 0, 0, pack);
+ if (errno == EAGAIN || errno == EACCES)
+ return thrd_nomem;
+ return thrd_error;
+ }
+ thr->handle = (void *) handle;
+ pack->thrd = *thr;
+ ResumeThread((HANDLE) handle);
+ return thrd_success;
+}
+int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) {
+ return thrd_create_with_stack(thr, func, arg, 0);
+}
+thrd_t thrd_current(void) {
+ /* GetCurrentThread() returns a pseudo-handle, which we need
+ * to pass to DuplicateHandle(). Only the resulting handle can be
+ * used from other threads.
+ *
+ * Note that neither handle can be compared to the one by
+ * thread_create. Only the thread IDs - as returned by GetThreadId()
+ * and GetCurrentThreadId() can be compared directly.
+ *
+ * Other potential solutions would be:
+ * - define thrd_t as a thread Ids, but this would mean we'd need to
+ * OpenThread for many operations
+ * - use malloc'ed memory for thrd_t. This would imply using TLS for
+ * current thread.
+ *
+ * Neither is particularly nice.
+ *
+ * Life would be much easier if C11 threads had different
+ * abstractions for threads and thread IDs, just like C++11 threads
+ * does...
+ */
+ struct thrd_state *state = &impl_current_thread;
+ if (state->thrd.handle == NULL) {
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &(state->thrd.handle),
+ 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ abort();
+ }
+ state->handle_need_close = true;
+ }
+ return state->thrd;
+}
+int thrd_detach(thrd_t thr) {
+ CloseHandle(thr.handle);
+ return thrd_success;
+}
+int thrd_equal(thrd_t thr0, thrd_t thr1) {
+ return GetThreadId(thr0.handle) == GetThreadId(thr1.handle);
+}
+_Noreturn void thrd_exit(int res) {
+ _endthreadex((unsigned) res);
+}
+int thrd_join(thrd_t thr, int *res) {
+ DWORD w, code;
+ if (thr.handle == NULL) {
+ return thrd_error;
+ }
+ w = WaitForSingleObject(thr.handle, INFINITE);
+ if (w != WAIT_OBJECT_0)
+ return thrd_error;
+ if (res) {
+ if (!GetExitCodeThread(thr.handle, &code)) {
+ CloseHandle(thr.handle);
+ return thrd_error;
+ }
+ *res = (int) code;
+ }
+ CloseHandle(thr.handle);
+ return thrd_success;
+}
+int thrd_sleep(const struct timespec *time_point,
+ struct timespec *remaining) {
+ (void) remaining;
+ assert(time_point);
+ assert(!remaining); /* not implemented */
+ Sleep((DWORD) impl_timespec2msec(time_point));
+ return 0;
+}
+void thrd_yield(void) {
+ SwitchToThread();
+}
+# endif
+#endif
/*********************************************************************
* *
- * File: ./source/kit/dynamic_array.c *
+ * File: source/kit/atomic.win32.c *
+ * *
+ *********************************************************************/
+#ifdef _MSC_VER
+static_assert(sizeof(char) == 1, "Wrong char size");
+static_assert(sizeof(short) == 2, "Wrong short size");
+static_assert(sizeof(int) == 4, "Wrong int size");
+# include <intrin.h>
+void kit_atomic_store_explicit_8(uint8_t volatile *var, uint8_t value,
+ int memory_order) {
+ char volatile *dst = (char volatile *) var;
+ char src = (char) value;
+ switch (memory_order) {
+ case memory_order_relaxed: *dst = src; break;
+ default: _InterlockedExchange8(dst, src);
+ }
+}
+void kit_atomic_store_explicit_16(uint16_t volatile *var,
+ uint16_t value, int memory_order) {
+ short volatile *dst = (short volatile *) var;
+ short src = (short) value;
+ switch (memory_order) {
+ case memory_order_relaxed: *dst = src; break;
+ default: _InterlockedExchange16(dst, src);
+ }
+}
+void kit_atomic_store_explicit_32(uint32_t volatile *var,
+ uint32_t value, int memory_order) {
+ int volatile *dst = (int volatile *) var;
+ int src = (int) value;
+ switch (memory_order) {
+ case memory_order_relaxed: *dst = src; break;
+ default: _InterlockedExchange(dst, src);
+ }
+}
+void kit_atomic_store_explicit_64(uint64_t volatile *var,
+ uint64_t value, int memory_order) {
+ __int64 volatile *dst = (__int64 volatile *) var;
+ __int64 src = (__int64) value;
+ switch (memory_order) {
+ case memory_order_relaxed: *dst = src; break;
+ default:
+# ifdef _WIN64
+ _InterlockedExchange64(dst, src);
+# else
+ _InterlockedExchange((int volatile *) dst, (int) src);
+# endif
+ }
+}
+uint8_t kit_atomic_load_explicit_8(volatile uint8_t *var,
+ int memory_order) {
+ char volatile *dst = (char volatile *) var;
+ if (memory_order == memory_order_relaxed)
+ return (uint8_t) *dst;
+ return (uint8_t) _InterlockedOr8(dst, 0);
+}
+uint16_t kit_atomic_load_explicit_16(uint16_t volatile *var,
+ int memory_order) {
+ short volatile *dst = (short volatile *) var;
+ if (memory_order == memory_order_relaxed)
+ return (uint16_t) *dst;
+ return (uint16_t) _InterlockedOr16(dst, 0);
+}
+uint32_t kit_atomic_load_explicit_32(uint32_t volatile *var,
+ int memory_order) {
+ int volatile *dst = (int volatile *) var;
+ if (memory_order == memory_order_relaxed)
+ return (uint32_t) *dst;
+ return (uint32_t) _InterlockedOr(dst, 0);
+}
+uint64_t kit_atomic_load_explicit_64(uint64_t volatile *var,
+ int memory_order) {
+ __int64 volatile *dst = (__int64 volatile *) var;
+ if (memory_order == memory_order_relaxed)
+ return (uint64_t) *dst;
+# ifdef _WIN64
+ return (uint64_t) _InterlockedOr64(dst, 0);
+# else
+ return (uint64_t) _InterlockedOr((int volatile *) dst, 0);
+# endif
+}
+uint8_t kit_atomic_exchange_explicit_8(volatile uint8_t *var,
+ uint8_t value,
+ int memory_order) {
+ char volatile *dst = (char volatile *) var;
+ char src = (char) value;
+ return (uint8_t) _InterlockedExchange8(dst, src);
+}
+uint16_t kit_atomic_exchange_explicit_16(uint16_t volatile *var,
+ uint16_t value,
+ int memory_order) {
+ short volatile *dst = (short volatile *) var;
+ short src = (short) value;
+ return (uint16_t) _InterlockedExchange16(dst, src);
+}
+uint32_t kit_atomic_exchange_explicit_32(uint32_t volatile *var,
+ uint32_t value,
+ int memory_order) {
+ int volatile *dst = (int volatile *) var;
+ int src = (int) value;
+ return (uint32_t) _InterlockedExchange(dst, src);
+}
+uint64_t kit_atomic_exchange_explicit_64(uint64_t volatile *var,
+ uint64_t value,
+ int memory_order) {
+ __int64 volatile *dst = (__int64 volatile *) var;
+ __int64 src = (__int64) value;
+# ifdef _WIN64
+ return (uint64_t) _InterlockedExchange64(dst, src);
+# else
+ return (uint64_t) _InterlockedExchange((int volatile *) dst,
+ (int) src);
+# endif
+}
+uint8_t kit_atomic_fetch_add_explicit_8(volatile uint8_t *var,
+ uint8_t value,
+ int memory_order) {
+ char volatile *dst = (char volatile *) var;
+ char src = (char) value;
+ return (uint8_t) _InterlockedExchangeAdd8(dst, src);
+}
+uint16_t kit_atomic_fetch_add_explicit_16(uint16_t volatile *var,
+ uint16_t value,
+ int memory_order) {
+ short volatile *dst = (short volatile *) var;
+ short src = (short) value;
+ return (uint16_t) _InterlockedExchangeAdd16(dst, src);
+}
+uint32_t kit_atomic_fetch_add_explicit_32(uint32_t volatile *var,
+ uint32_t value,
+ int memory_order) {
+ int volatile *dst = (int volatile *) var;
+ int src = (int) value;
+ return (uint32_t) _InterlockedExchangeAdd(dst, src);
+}
+uint64_t kit_atomic_fetch_add_explicit_64(uint64_t volatile *var,
+ uint64_t value,
+ int memory_order) {
+ __int64 volatile *dst = (__int64 volatile *) var;
+ __int64 src = (__int64) value;
+# ifdef _WIN64
+ return (uint64_t) _InterlockedExchangeAdd64(dst, src);
+# else
+ return (uint64_t) _InterlockedExchangeAdd((int volatile *) dst,
+ (int) src);
+# endif
+}
+#endif
+/*********************************************************************
+ * *
+ * File: source/kit/mutex.c *
+ * *
+ *********************************************************************/
+/*********************************************************************
+ * *
+ * File: source/kit/condition_variable.c *
+ * *
+ *********************************************************************/
+/*********************************************************************
+ * *
+ * File: source/kit/dynamic_array.c *
* *
*********************************************************************/
#include <assert.h>
@@ -485,7 +2559,6 @@ void kit_da_init(kit_da_void_t *array, ptrdiff_t element_size,
assert(array != NULL);
assert(element_size > 0);
assert(size >= 0);
- assert(alloc.allocate != NULL);
memset(array, 0, sizeof(kit_da_void_t));
if (size > 0)
array->values = kit_alloc_dispatch(alloc, KIT_ALLOCATE,
@@ -513,7 +2586,6 @@ void kit_da_resize(kit_da_void_t *array, ptrdiff_t element_size,
array->size = size;
} else {
ptrdiff_t capacity = eval_capacity(array->capacity, size);
- assert(array->alloc.allocate != NULL);
void *bytes = kit_alloc_dispatch(
array->alloc, KIT_ALLOCATE, element_size * capacity, 0, NULL);
if (bytes != NULL) {
@@ -530,7 +2602,194 @@ void kit_da_resize(kit_da_void_t *array, ptrdiff_t element_size,
}
/*********************************************************************
* *
- * File: ./source/kit/file.c *
+ * File: source/kit/input_stream.c *
+ * *
+ *********************************************************************/
+#include <string.h>
+enum { input_stream_str };
+typedef struct {
+ ptrdiff_t type;
+ kit_allocator_t alloc;
+} kit_is_state_basic_t;
+typedef struct {
+ ptrdiff_t type;
+ kit_allocator_t alloc;
+ kit_str_t string;
+} kit_is_state_str_t;
+static int check_type(void *state, ptrdiff_t type) {
+ kit_is_state_basic_t *basic = (kit_is_state_basic_t *) state;
+ return basic != NULL && basic->type == type;
+}
+static ptrdiff_t read_str(void *state, kit_str_t destination) {
+ if (!check_type(state, input_stream_str))
+ return 0;
+ kit_is_state_str_t *str = (kit_is_state_str_t *) state;
+ ptrdiff_t size = destination.size < str->string.size
+ ? destination.size
+ : str->string.size;
+ memcpy(destination.values, str->string.values, size);
+ str->string.values += size;
+ str->string.size -= size;
+ return size;
+}
+kit_is_handle_t kit_is_wrap_string(kit_str_t string,
+ kit_allocator_t alloc) {
+ kit_is_handle_t in;
+ memset(&in, 0, sizeof in);
+ kit_is_state_str_t *state = (kit_is_state_str_t *)
+ kit_alloc_dispatch(alloc, KIT_ALLOCATE,
+ sizeof(kit_is_state_str_t), 0, NULL);
+ if (state != NULL) {
+ memset(state, 0, sizeof *state);
+ state->type = input_stream_str;
+ state->string = string;
+ state->alloc = alloc;
+ in.state = state;
+ in.read = read_str;
+ }
+ return in;
+}
+void kit_is_destroy(kit_is_handle_t in) {
+ kit_is_state_basic_t *basic = (kit_is_state_basic_t *) in.state;
+ if (basic != NULL)
+ kit_alloc_dispatch(basic->alloc, KIT_DEALLOCATE, 0, 0, in.state);
+}
+/*********************************************************************
+ * *
+ * File: source/kit/input_buffer.c *
+ * *
+ *********************************************************************/
+#include <assert.h>
+#include <string.h>
+typedef struct {
+ ptrdiff_t ref_count;
+ kit_is_handle_t upstream;
+ kit_allocator_t alloc;
+ kit_string_t data;
+} internal_buffer_t;
+static internal_buffer_t *buf_init(kit_is_handle_t upstream,
+ kit_allocator_t alloc) {
+ assert(alloc.allocate != NULL);
+ internal_buffer_t *buf = kit_alloc_dispatch(alloc, KIT_ALLOCATE,
+ sizeof *buf, 0, NULL);
+ if (buf != NULL) {
+ memset(buf, 0, sizeof *buf);
+ buf->ref_count = 1;
+ buf->upstream = upstream;
+ buf->alloc = alloc;
+ DA_INIT(buf->data, 0, alloc);
+ }
+ return buf;
+}
+static kit_allocator_t buf_alloc(void *p) {
+ assert(p != NULL);
+ return ((internal_buffer_t *) p)->alloc;
+}
+static void buf_acquire(void *p) {
+ assert(p != NULL);
+ ((internal_buffer_t *) p)->ref_count++;
+}
+static void buf_release(void *p) {
+ assert(p != NULL);
+ internal_buffer_t *buf = (internal_buffer_t *) p;
+ if (--buf->ref_count == 0) {
+ DA_DESTROY(buf->data);
+ kit_alloc_dispatch(buf->alloc, KIT_DEALLOCATE, 0, 0, buf);
+ }
+}
+static void buf_adjust(void *p, ptrdiff_t size) {
+ assert(p != NULL);
+ assert(size >= 0);
+ internal_buffer_t *buf = (internal_buffer_t *) p;
+ ptrdiff_t offset = buf->data.size;
+ if (offset < size) {
+ DA_RESIZE(buf->data, size);
+ kit_str_t destination = { .size = size - offset,
+ .values = buf->data.values + offset };
+ ptrdiff_t n = KIT_IS_READ(buf->upstream, destination);
+ DA_RESIZE(buf->data, offset + n);
+ }
+}
+static ptrdiff_t buf_read(void *p, ptrdiff_t offset,
+ kit_str_t destination) {
+ internal_buffer_t *buf = (internal_buffer_t *) p;
+ ptrdiff_t n = destination.size < buf->data.size - offset
+ ? destination.size
+ : buf->data.size - offset;
+ memcpy(destination.values, buf->data.values + offset, n);
+ return n;
+}
+kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream,
+ kit_allocator_t alloc) {
+ kit_ib_handle_t buf;
+ memset(&buf, 0, sizeof buf);
+ buf.status = KIT_OK;
+ DA_INIT(buf.data, 0, alloc);
+ buf.internal = buf_init(upstream, alloc);
+ if (buf.internal == NULL)
+ buf.status = KIT_ERROR_BAD_ALLOC;
+ return buf;
+}
+kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, ptrdiff_t size) {
+ kit_ib_handle_t next;
+ memset(&next, 0, sizeof next);
+ if (buf.status != KIT_OK) {
+ next.status = buf.status;
+ return next;
+ }
+ buf_acquire(buf.internal);
+ buf_adjust(buf.internal, buf.offset + size);
+ DA_INIT(next.data, size, buf_alloc(buf.internal));
+ if (next.data.size != size)
+ next.status = KIT_ERROR_BAD_ALLOC;
+ kit_str_t destination = { .size = next.data.size,
+ .values = next.data.values };
+ ptrdiff_t n = buf_read(buf.internal, buf.offset, destination);
+ next.offset = buf.offset + n;
+ next.internal = buf.internal;
+ DA_RESIZE(next.data, n);
+ if (next.data.size != n)
+ next.status = KIT_ERROR_BAD_ALLOC;
+ return next;
+}
+kit_ib_handle_t kit_ib_read_while(
+ kit_ib_handle_t buf, kit_ib_read_condition_fn condition) {
+ kit_ib_handle_t next;
+ memset(&next, 0, sizeof next);
+ if (buf.status != KIT_OK) {
+ next.status = buf.status;
+ return next;
+ }
+ buf_acquire(buf.internal);
+ DA_INIT(next.data, 0, buf_alloc(buf.internal));
+ ptrdiff_t size = 0;
+ for (;; ++size) {
+ buf_adjust(buf.internal, buf.offset + size + 1);
+ DA_RESIZE(next.data, size + 1);
+ if (next.data.size != size + 1)
+ next.status = KIT_ERROR_BAD_ALLOC;
+ kit_str_t destination = { .size = 1,
+ .values = next.data.values + size };
+ ptrdiff_t n = buf_read(buf.internal, buf.offset + size,
+ destination);
+ kit_str_t data = { .size = size + 1, .values = next.data.values };
+ if (n != 1 || condition == NULL || condition(data) == 0)
+ break;
+ }
+ next.offset = buf.offset + size;
+ next.internal = buf.internal;
+ DA_RESIZE(next.data, size);
+ if (next.data.size != size)
+ next.status = KIT_ERROR_BAD_ALLOC;
+ return next;
+}
+void kit_ib_destroy(kit_ib_handle_t buf) {
+ buf_release(buf.internal);
+ DA_DESTROY(buf.data);
+}
+/*********************************************************************
+ * *
+ * File: source/kit/file.c *
* *
*********************************************************************/
#include <assert.h>
@@ -551,13 +2810,12 @@ enum { PATH_BUF_SIZE = 4096 };
#ifdef __APPLE__
# define st_mtim st_mtimespec
#endif
-static int is_delim(char const c) {
+static int is_delim(char c) {
return c == '/' || c == '\\';
}
-static kit_string_t kit_get_env_(char *const name,
- kit_allocator_t const alloc) {
- char *const val = getenv(name);
- ptrdiff_t const size = val != NULL ? (ptrdiff_t) strlen(val) : 0;
+static kit_string_t kit_get_env_(char *name, kit_allocator_t alloc) {
+ char *val = getenv(name);
+ ptrdiff_t size = val != NULL ? (ptrdiff_t) strlen(val) : 0;
string_t result;
DA_INIT(result, size, alloc);
assert(result.size == size);
@@ -567,10 +2825,9 @@ static kit_string_t kit_get_env_(char *const name,
DA_RESIZE(result, 0);
return result;
}
-kit_string_t kit_path_norm(kit_str_t const path,
- kit_allocator_t const alloc) {
- str_t const parent = SZ("..");
- ptrdiff_t i, i1, j;
+kit_string_t kit_path_norm(kit_str_t path, kit_allocator_t alloc) {
+ str_t parent = SZ("..");
+ ptrdiff_t i, i1, j;
string_t norm;
DA_INIT(norm, path.size, alloc);
assert(norm.size == path.size);
@@ -580,8 +2837,7 @@ kit_string_t kit_path_norm(kit_str_t const path,
for (i1 = 0, i = 0; i < path.size; i++) {
if (!is_delim(path.values[i]))
continue;
- str_t const s = { .size = i - i1 - 1,
- .values = path.values + i1 + 1 };
+ str_t s = { .size = i - i1 - 1, .values = path.values + i1 + 1 };
if (AR_EQUAL(s, parent)) {
int have_parent = 0;
ptrdiff_t i0 = 0;
@@ -612,12 +2868,11 @@ kit_string_t kit_path_norm(kit_str_t const path,
norm.size = size;
return norm;
}
-kit_string_t kit_path_join(kit_str_t const left,
- kit_str_t const right,
- kit_allocator_t const alloc) {
- ptrdiff_t left_size = left.size;
- ptrdiff_t right_size = right.size;
- char const *right_values = right.values;
+kit_string_t kit_path_join(kit_str_t left, kit_str_t right,
+ kit_allocator_t alloc) {
+ ptrdiff_t left_size = left.size;
+ ptrdiff_t right_size = right.size;
+ char *right_values = right.values;
if (left_size > 0 && is_delim(left.values[left_size - 1]))
left_size--;
if (right_size > 0 && is_delim(right.values[0])) {
@@ -634,7 +2889,7 @@ kit_string_t kit_path_join(kit_str_t const left,
memcpy(joined.values + left_size + 1, right_values, right_size);
return joined;
}
-kit_string_t kit_path_user(kit_allocator_t const alloc) {
+kit_string_t kit_path_user(kit_allocator_t alloc) {
kit_string_t user = kit_get_env_(KIT_ENV_HOME, alloc);
if (user.size == 0) {
DA_RESIZE(user, 1);
@@ -666,8 +2921,7 @@ kit_string_t kit_path_cache(kit_allocator_t alloc) {
DA_DESTROY(user);
return cache;
}
-kit_str_t kit_path_index(kit_str_t const path,
- ptrdiff_t const index) {
+kit_str_t kit_path_index(kit_str_t path, ptrdiff_t index) {
str_t s = { .size = 0, .values = NULL };
ptrdiff_t i0 = 0;
ptrdiff_t i = 0;
@@ -690,7 +2944,7 @@ kit_str_t kit_path_index(kit_str_t const path,
}
return s;
}
-kit_str_t kit_path_take(kit_str_t const path, ptrdiff_t const count) {
+kit_str_t kit_path_take(kit_str_t path, ptrdiff_t count) {
str_t s = { .size = 0, .values = path.values };
ptrdiff_t i0 = 0;
ptrdiff_t i = 0;
@@ -711,8 +2965,7 @@ kit_str_t kit_path_take(kit_str_t const path, ptrdiff_t const count) {
return s;
}
#if defined(_WIN32) && !defined(__CYGWIN__)
-static void win32_prepare_path_(WCHAR *const buf,
- kit_str_t const path) {
+static void win32_prepare_path_(WCHAR *buf, kit_str_t path) {
assert(path.size == 0 || path.values != NULL);
assert(path.size + 5 < PATH_BUF_SIZE);
memset(buf, 0, PATH_BUF_SIZE);
@@ -732,8 +2985,7 @@ static void win32_prepare_path_(WCHAR *const buf,
WCHAR buf[PATH_BUF_SIZE]; \
win32_prepare_path_(buf, path)
#else
-static void unix_prepare_path_(char *const buf,
- kit_str_t const path) {
+static void unix_prepare_path_(char *buf, kit_str_t path) {
assert(path.size == 0 || path.values != NULL);
assert(path.size + 1 < PATH_BUF_SIZE);
memset(buf, 0, PATH_BUF_SIZE);
@@ -744,7 +2996,7 @@ static void unix_prepare_path_(char *const buf,
char buf[PATH_BUF_SIZE]; \
unix_prepare_path_(buf, path)
#endif
-kit_status_t kit_file_create_folder(kit_str_t const path) {
+kit_status_t kit_file_create_folder(kit_str_t path) {
PREPARE_PATH_BUF_;
#if defined(_WIN32) && !defined(__CYGWIN__)
return CreateDirectoryW(buf, NULL) ? KIT_OK
@@ -753,15 +3005,15 @@ kit_status_t kit_file_create_folder(kit_str_t const path) {
return mkdir(buf, 0755) == 0 ? KIT_OK : KIT_ERROR_MKDIR_FAILED;
#endif
}
-kit_status_t kit_file_create_folder_recursive(kit_str_t const path) {
+kit_status_t kit_file_create_folder_recursive(kit_str_t path) {
ptrdiff_t i;
for (i = 0;; i++) {
- str_t const part = kit_path_take(path, i);
- int const type = kit_path_type(part);
+ str_t part = kit_path_take(path, i);
+ int type = kit_path_type(part);
if (type == KIT_PATH_FILE)
return KIT_ERROR_FILE_ALREADY_EXISTS;
if (type == KIT_PATH_NONE) {
- kit_status_t const s = kit_file_create_folder(part);
+ kit_status_t s = kit_file_create_folder(part);
if (s != KIT_OK)
return s;
}
@@ -770,7 +3022,7 @@ kit_status_t kit_file_create_folder_recursive(kit_str_t const path) {
}
return KIT_OK;
}
-kit_status_t kit_file_remove(kit_str_t const path) {
+kit_status_t kit_file_remove(kit_str_t path) {
PREPARE_PATH_BUF_;
#if defined(_WIN32) && !defined(__CYGWIN__)
return DeleteFileW(buf) ? KIT_OK : KIT_ERROR_UNLINK_FAILED;
@@ -778,7 +3030,7 @@ kit_status_t kit_file_remove(kit_str_t const path) {
return unlink(buf) == 0 ? KIT_OK : KIT_ERROR_UNLINK_FAILED;
#endif
}
-kit_status_t kit_file_remove_folder(kit_str_t const path) {
+kit_status_t kit_file_remove_folder(kit_str_t path) {
PREPARE_PATH_BUF_;
#if defined(_WIN32) && !defined(__CYGWIN__)
return RemoveDirectoryW(buf) ? KIT_OK : KIT_ERROR_RMDIR_FAILED;
@@ -786,8 +3038,8 @@ kit_status_t kit_file_remove_folder(kit_str_t const path) {
return rmdir(buf) == 0 ? KIT_OK : KIT_ERROR_RMDIR_FAILED;
#endif
}
-kit_status_t kit_file_remove_recursive(kit_str_t const path,
- kit_allocator_t const alloc) {
+kit_status_t kit_file_remove_recursive(kit_str_t path,
+ kit_allocator_t alloc) {
int type = kit_path_type(path);
ptrdiff_t i;
switch (type) {
@@ -799,8 +3051,8 @@ kit_status_t kit_file_remove_recursive(kit_str_t const path,
return list.status;
}
for (i = 0; i < list.files.size; i++) {
- str_t const s = { .size = list.files.values[i].size,
- .values = list.files.values[i].values };
+ str_t s = { .size = list.files.values[i].size,
+ .values = list.files.values[i].values };
kit_file_remove_recursive(s, alloc);
}
kit_path_list_destroy(list);
@@ -810,7 +3062,7 @@ kit_status_t kit_file_remove_recursive(kit_str_t const path,
}
return KIT_ERROR_FILE_DO_NOT_EXIST;
}
-kit_path_type_t kit_path_type(kit_str_t const path) {
+kit_path_type_t kit_path_type(kit_str_t path) {
PREPARE_PATH_BUF_;
#if defined(_WIN32) && !defined(__CYGWIN__)
if (PathFileExistsW(buf)) {
@@ -830,7 +3082,7 @@ kit_path_type_t kit_path_type(kit_str_t const path) {
#endif
return KIT_PATH_NONE;
}
-kit_file_info_t kit_file_info(kit_str_t const path) {
+kit_file_info_t kit_file_info(kit_str_t path) {
kit_file_info_t result;
memset(&result, 0, sizeof result);
PREPARE_PATH_BUF_;
@@ -840,9 +3092,8 @@ kit_file_info_t kit_file_info(kit_str_t const path) {
if (f != INVALID_HANDLE_VALUE) {
FILETIME ft;
if (GetFileTime(f, NULL, NULL, &ft) != 0) {
- uint64_t const nsec100 = (((uint64_t) ft.dwHighDateTime)
- << 32) |
- (uint64_t) ft.dwLowDateTime;
+ uint64_t nsec100 = (((uint64_t) ft.dwHighDateTime) << 32) |
+ (uint64_t) ft.dwLowDateTime;
result.time_modified_sec = (int64_t) (nsec100 / 10000000);
result.time_modified_nsec = (int32_t) (100 *
(nsec100 % 10000000));
@@ -876,8 +3127,8 @@ kit_file_info_t kit_file_info(kit_str_t const path) {
result.status = KIT_ERROR_FILE_DO_NOT_EXIST;
return result;
}
-kit_path_list_t kit_file_enum_folder(kit_str_t const path,
- kit_allocator_t const alloc) {
+kit_path_list_t kit_file_enum_folder(kit_str_t path,
+ kit_allocator_t alloc) {
PREPARE_PATH_BUF_;
kit_path_list_t result = { .status = KIT_OK };
DA_INIT(result.files, 0, alloc);
@@ -893,7 +3144,7 @@ kit_path_list_t kit_file_enum_folder(kit_str_t const path,
if (find == INVALID_HANDLE_VALUE)
return result;
do {
- ptrdiff_t const n = result.files.size;
+ ptrdiff_t n = result.files.size;
DA_RESIZE(result.files, n + 1);
if (result.files.size != n + 1) {
result.status = KIT_ERROR_BAD_ALLOC;
@@ -921,13 +3172,13 @@ kit_path_list_t kit_file_enum_folder(kit_str_t const path,
break;
if (entry->d_name[0] == '.')
continue;
- ptrdiff_t const n = result.files.size;
+ ptrdiff_t n = result.files.size;
DA_RESIZE(result.files, n + 1);
if (result.files.size != n + 1) {
result.status = KIT_ERROR_BAD_ALLOC;
break;
}
- ptrdiff_t const size = (ptrdiff_t) strlen(entry->d_name);
+ ptrdiff_t size = (ptrdiff_t) strlen(entry->d_name);
DA_INIT(result.files.values[n], size, alloc);
if (result.files.values[n].size != size) {
DA_RESIZE(result.files, n);
@@ -947,4 +3198,275 @@ void kit_path_list_destroy(kit_path_list_t list) {
DA_DESTROY(list.files.values[i]);
DA_DESTROY(list.files);
}
+/*********************************************************************
+ * *
+ * File: source/kit/mersenne_twister_64.c *
+ * *
+ *********************************************************************/
+#define MM 156
+#define MATRIX_A 0xb5026f5aa96619e9ull
+#define UM 0xffffffff80000000ull
+#define LM 0x7fffffffull
+void kit_mt64_init_array(kit_mt64_state_t *state, ptrdiff_t size,
+ uint64_t *seed) {
+ ptrdiff_t i;
+ for (i = 0; i < size && i < KIT_MT64_N; i++) state->mt[i] = seed[i];
+ for (state->index = size; state->index < KIT_MT64_N; state->index++)
+ state->mt[state->index] = (6364136223846793005ull *
+ (state->mt[state->index - 1] ^
+ (state->mt[state->index - 1] >>
+ 62u)) +
+ state->index);
+}
+void kit_mt64_init(kit_mt64_state_t *state, uint64_t seed) {
+ kit_mt64_init_array(state, 1, &seed);
+}
+void kit_mt64_rotate(kit_mt64_state_t *state) {
+ static uint64_t mag01[2] = { 0ull, MATRIX_A };
+ uint64_t x;
+ int i;
+ for (i = 0; i < KIT_MT64_N - MM; i++) {
+ x = (state->mt[i] & UM) | (state->mt[i + 1] & LM);
+ state->mt[i] = state->mt[i + MM] ^ (x >> 1u) ^
+ mag01[(int) (x & 1ull)];
+ }
+ for (; i < KIT_MT64_N - 1; i++) {
+ x = (state->mt[i] & UM) | (state->mt[i + 1] & LM);
+ state->mt[i] = state->mt[i + (MM - KIT_MT64_N)] ^ (x >> 1u) ^
+ mag01[(int) (x & 1ull)];
+ }
+ x = (state->mt[KIT_MT64_N - 1] & UM) | (state->mt[0] & LM);
+ state->mt[KIT_MT64_N - 1] = state->mt[MM - 1] ^ (x >> 1u) ^
+ mag01[(int) (x & 1ull)];
+ state->index = 0;
+}
+uint64_t kit_mt64_generate(kit_mt64_state_t *state) {
+ if (state->index >= KIT_MT64_N)
+ kit_mt64_rotate(state);
+ uint64_t x = state->mt[state->index++];
+ x ^= (x >> 29u) & 0x5555555555555555ull;
+ x ^= (x << 17u) & 0x71d67fffeda60000ull;
+ x ^= (x << 37u) & 0xfff7eee000000000ull;
+ x ^= (x >> 43u);
+ return x;
+}
+/*********************************************************************
+ * *
+ * File: source/kit/secure_random.c *
+ * *
+ *********************************************************************/
+#include <assert.h>
+#include <stdio.h>
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# include <Windows.h>
+#else
+# include <unistd.h>
+#endif
+static uint64_t get_available_memory(void) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ MEMORYSTATUSEX status;
+ status.dwLength = sizeof(status);
+ GlobalMemoryStatusEx(&status);
+ return (uint64_t) status.ullTotalPhys;
+#else
+ uint64_t pages = (uint64_t) sysconf(_SC_PHYS_PAGES);
+ uint64_t page_size = (uint64_t) sysconf(_SC_PAGE_SIZE);
+ return pages * page_size;
+#endif
+}
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+static once_flag kit_secure_random_fallback_flag;
+static mtx_t kit_secure_random_fallback_mutex;
+static void secure_random_fallback_init(void) {
+ mtx_init(&kit_secure_random_fallback_mutex, mtx_plain);
+}
+#endif
+static void secure_random_fallback(ptrdiff_t size, void *data) {
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+ call_once(&kit_secure_random_fallback_flag,
+ secure_random_fallback_init);
+ mtx_lock(&kit_secure_random_fallback_mutex);
+#endif
+ /* Try to get some unpredictable system properties and use them to
+ * seed the pseudo random number generator.
+ */
+ static uint64_t n = 0;
+ static uint64_t time_sec = 0;
+ static uint64_t time_nsec = 0;
+ struct timespec t;
+ ptrdiff_t i;
+ timespec_get(&t, TIME_UTC);
+ kit_mt64_state_t state;
+ if (time_sec == 0 && time_nsec == 0) {
+ uint64_t seed[] = { n, get_available_memory(),
+ (uint64_t) t.tv_sec, (uint64_t) t.tv_nsec };
+ kit_mt64_init_array(&state, sizeof seed / sizeof *seed, seed);
+ } else {
+ uint64_t seed[] = { n,
+ get_available_memory(),
+ (uint64_t) t.tv_sec,
+ (uint64_t) t.tv_nsec,
+ (uint64_t) t.tv_sec - time_sec,
+ (uint64_t) t.tv_nsec - time_nsec };
+ kit_mt64_init_array(&state, sizeof seed / sizeof *seed, seed);
+ }
+ kit_mt64_rotate(&state);
+ n = kit_mt64_generate(&state);
+ time_sec = (uint64_t) t.tv_sec;
+ time_nsec = (uint64_t) t.tv_nsec;
+ for (i = 0; i < size; i++)
+ ((uint8_t *) data)[i] = (uint8_t) (kit_mt64_generate(&state) >>
+ 56);
+#ifndef KIT_DISABLE_SYSTEM_THREADS
+ mtx_unlock(&kit_secure_random_fallback_mutex);
+#endif
+}
+void kit_secure_random(ptrdiff_t size, void *data) {
+ assert(size > 0);
+ assert(data != NULL);
+ if (size <= 0 || data == NULL)
+ return;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ secure_random_fallback(size, data);
+#else
+ FILE *f = fopen("/dev/urandom", "rb");
+ assert(f != NULL);
+ if (f == NULL) {
+ secure_random_fallback(size, data);
+ return;
+ }
+ size_t n = fread(data, 1, size, f);
+ fclose(f);
+ assert(n == size);
+ if (n != size)
+ secure_random_fallback(size, data);
+#endif
+}
+/*********************************************************************
+ * *
+ * File: source/kit/sha256.c *
+ * *
+ *********************************************************************/
+#include <assert.h>
+#include <string.h>
+#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
+#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
+#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22))
+#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25))
+#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10))
+static uint32_t kit_sha256_k[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
+ 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
+ 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
+ 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
+ 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
+ 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
+ 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
+ 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
+ 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+static void kit_sha256_transform(uint32_t *state, uint8_t *data) {
+ assert(state != NULL);
+ assert(data != NULL);
+ uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
+ m[i] = ((uint32_t) data[j] << 24) |
+ ((uint32_t) data[j + 1] << 16) |
+ ((uint32_t) data[j + 2] << 8) | ((uint32_t) data[j + 3]);
+ for (; i < 64; ++i)
+ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ f = state[5];
+ g = state[6];
+ h = state[7];
+ for (i = 0; i < 64; ++i) {
+ t1 = h + EP1(e) + CH(e, f, g) + kit_sha256_k[i] + m[i];
+ t2 = EP0(a) + MAJ(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ state[5] += f;
+ state[6] += g;
+ state[7] += h;
+}
+kit_sha256_hash_t kit_sha256(ptrdiff_t in_size, uint8_t *in_data) {
+ assert(in_size >= 0);
+ assert(in_data != NULL);
+ uint32_t state[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372,
+ 0xa54ff53a, 0x510e527f, 0x9b05688c,
+ 0x1f83d9ab, 0x5be0cd19 };
+ uint8_t data[64];
+ ptrdiff_t i;
+ ptrdiff_t datalen = 0;
+ uint64_t bitlen = 0;
+ if (in_data != NULL)
+ for (i = 0; i < in_size; ++i) {
+ data[datalen] = in_data[i];
+ datalen++;
+ if (datalen != 64)
+ continue;
+ kit_sha256_transform(state, data);
+ bitlen += 512;
+ datalen = 0;
+ }
+ i = datalen;
+ if (datalen < 56) {
+ data[i++] = 0x80;
+ while (i < 56) data[i++] = 0x00;
+ } else {
+ data[i++] = 0x80;
+ while (i < 64) data[i++] = 0x00;
+ kit_sha256_transform(state, data);
+ memset(data, 0, 56);
+ }
+ bitlen += datalen * 8;
+ data[63] = bitlen;
+ data[62] = bitlen >> 8;
+ data[61] = bitlen >> 16;
+ data[60] = bitlen >> 24;
+ data[59] = bitlen >> 32;
+ data[58] = bitlen >> 40;
+ data[57] = bitlen >> 48;
+ data[56] = bitlen >> 56;
+ kit_sha256_transform(state, data);
+ kit_sha256_hash_t hash;
+ memset(&hash, 0, sizeof hash);
+ for (i = 0; i < 4; ++i) {
+ hash.v[i] = (state[0] >> (24 - i * 8)) & 0xff;
+ hash.v[i + 4] = (state[1] >> (24 - i * 8)) & 0xff;
+ hash.v[i + 8] = (state[2] >> (24 - i * 8)) & 0xff;
+ hash.v[i + 12] = (state[3] >> (24 - i * 8)) & 0xff;
+ hash.v[i + 16] = (state[4] >> (24 - i * 8)) & 0xff;
+ hash.v[i + 20] = (state[5] >> (24 - i * 8)) & 0xff;
+ hash.v[i + 24] = (state[6] >> (24 - i * 8)) & 0xff;
+ hash.v[i + 28] = (state[7] >> (24 - i * 8)) & 0xff;
+ }
+ return hash;
+}
+#endif
#endif