/******************************************************************************/
/* HashSet for C99, by LoRd_MuldeR <MuldeR2@GMX.de>                           */
/* This work has been released under the CC0 1.0 Universal license!           */
/******************************************************************************/

#ifndef _LIBHASHSET_COMMON_INCLUDED
#define _LIBHASHSET_COMMON_INCLUDED

/* CRT */
#include <string.h>
#include <errno.h>
#include <math.h>
#include <limits.h>
#include <float.h>
#include <assert.h>

typedef int bool_t;
#define TRUE  1
#define FALSE 0

#if defined(__GNUC__)
#  define INLINE __inline__
#  define FORCE_INLINE __attribute__((always_inline)) __inline__
#elif defined(_MSC_VER)
#  define INLINE __inline
#  define FORCE_INLINE __forceinline
#else
#  define INLINE
#endif

static const size_t MINIMUM_CAPACITY =  128U;
static const size_t DEFAULT_CAPACITY = 8192U;
static const double DEFAULT_LOADFCTR =   0.8;

/* ------------------------------------------------- */
/* Utilities                                         */
/* ------------------------------------------------- */

#define IS_VALID(X,Y) (get_flag((X).used, (Y)) && (!get_flag((X).deleted, (Y))))

#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL)))

#define SAFE_SET(X,Y) do { if((X)) { *(X) = (Y); } } while(0)

#define SAFE_FREE(X) do { if ((X)) { free((X)); (X) = NULL; } } while(0)

/* ------------------------------------------------- */
/* Math                                              */
/* ------------------------------------------------- */

static FORCE_INLINE size_t div_ceil(const size_t value, const size_t divisor)
{
	return (value / divisor) + ((value % divisor != 0U) ? 1U : 0U);
}

static FORCE_INLINE size_t round_sz(const double d)
{

	return ((!isnan(d)) && (d >= 0.0)) ? ((d + 0.5 >= ((double)SIZE_MAX)) ? SIZE_MAX : ((size_t)(d + 0.5))) : 0U;
}

static FORCE_INLINE size_t safe_add(const size_t a, const size_t b)
{
	return ((SIZE_MAX - a) > b) ? (a + b) : SIZE_MAX;
}

static FORCE_INLINE size_t safe_incr(const size_t value)
{
	return (value < SIZE_MAX) ? (value + 1U) : value;
}

static FORCE_INLINE size_t safe_decr(const size_t value)
{
	return (value > 0U) ? (value - 1U) : value;
}

static FORCE_INLINE size_t safe_mult(const size_t a, const size_t b)
{
	const size_t result = a * b;
	return ((a == 0U) || (result / a == b)) ? result : SIZE_MAX;
}

static FORCE_INLINE size_t safe_times2(const size_t value)
{
	return (value <= (SIZE_MAX / 2U)) ? (2U * value) : SIZE_MAX;
}

static FORCE_INLINE size_t next_pow2(const size_t target)
{
	size_t result = MINIMUM_CAPACITY;

	while (result < target)
	{
		result = safe_times2(result);
	}

	return result;
}

/* ------------------------------------------------- */
/* Hash function                                     */
/* ------------------------------------------------- */

static FORCE_INLINE void hash_update(uint64_t *const hash, uint64_t value)
{
	do
	{
		*hash ^= value & 0xFF;
		*hash *= UINT64_C(1099511628211);
	}
	while (value >>= CHAR_BIT);
}

static INLINE uint64_t hash_compute(const uint64_t i, const uint64_t value)
{
	uint64_t hash = UINT64_C(14695981039346656037);
	hash_update(&hash, i);
	hash_update(&hash, value);
	return hash;
}

/* ------------------------------------------------- */
/* Memory                                            */
/* ------------------------------------------------- */

static INLINE void zero_memory(void *const addr, const size_t count, const size_t size)
{
	memset(addr, 0, safe_mult(count, size));
}

/* ------------------------------------------------- */
/* Flags                                             */
/* ------------------------------------------------- */

static INLINE bool_t get_flag(const uint8_t *const flags, const size_t index)
{
	return (flags[index / 8U] >> (index % 8U)) & UINT8_C(1);
}

static INLINE void set_flag(uint8_t *const flags, const size_t index)
{
	flags[index / 8U] |= UINT8_C(1) << (index % 8U);
}

static INLINE void clear_flag(uint8_t *const flags, const size_t index)
{
	flags[index / 8U] &= ~(UINT8_C(1) << (index % 8U));
}

#endif /* _LIBHASHSET_COMMON_INCLUDED */