/*
 * frost_common.h
 *
 *  Created on: Jul 1, 2012
 *      Author: ergino
 */

#ifndef FROST_COMMON_H_
#define FROST_COMMON_H_

#include "frost/frost_basictypes.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
#include <limits.h>
#include <stdint.h>

/*
 * Macros
 */
#define FROST_N_ELEMENTS(s)      (sizeof(s) / sizeof ((s) [0]))
#define FROST_STR_DELIMITERS "_-|> <."

#define FROST_MAXINT             INT_MAX
#define FROST_MININT             INT_MIN
#define FROST_MAXINT32           INT32_MAX
#define FROST_MININT32           INT32_MIN
#define FROST_MININT64           INT64_MIN
#define FROST_MAXINT64           INT64_MAX
#define FROST_MAXUINT64          UINT64_MAX
#define FROST_MAXUINT            UINT_MAX


#define FROST_LITTLE_ENDIAN 1234
#define FROST_BYTE_ORDER             FROST_LITTLE_ENDIAN
#define FROST_BIFROST_ENDIAN    4321
#define FROST_STMT_START    do
#define FROST_STMT_END      while (0)

#define FROST_USEC_PER_SEC  1000000

#define ABS(a)         ((a) > 0 ? (a) : -(a))

#define FROST_STRUCT_OFFSET(p_type,field) offsetof(p_type,field)

#define EGLIB_STRINGIFY(x) #x
#define EGLIB_TOSTRING(x) EGLIB_STRINGIFY(x)
#define FROST_STRLOC __FILE__ ":" EGLIB_TOSTRING(__LINE__) ":"

#define FROST_CONST_RETURN const

#define CURRENT_PACKET_SIZE             get_packet_size()
#define CURRENT_MAX_PACKET_SIZE         (3*4096L)

#ifdef __cplusplus
extern "C"
{
#endif

#define frost_new(type,size)        ((type *) frost_malloc (sizeof (type) * (size)))
#define frost_new0(type,size)       ((type *) frost_calloc (sizeof (type)* (size)))

frost_long get_packet_size();
void set_packet_size(frost_long size);

typedef struct {
    frost_pointer (*malloc)      (frost_ulong    n_bytes);
    frost_pointer (*realloc)     (frost_pointer mem, frost_ulong n_bytes);
    void     (*free)        (frost_pointer mem);
    frost_pointer (*calloc)      (frost_ulong    n_blocks, frost_ulong n_block_bytes);
    frost_pointer (*try_malloc)  (frost_ulong    n_bytes);
    frost_pointer (*try_realloc) (frost_pointer mem, frost_ulong n_bytes);
} FROSTMemVTable;

#define frost_mem_set_vtable(x)

struct _FROSTMemChunk {
    frost_uint alloc_size;
};

typedef struct _FROSTMemChunk FROSTMemChunk;
/*
 * Misc.
 */
#define frost_atexit(func)  ((void) atexit (func))

const char *    frost_getenv(const char *variable);
frost_bool         frost_setenv(const char *variable, const char *value, frost_bool overwrite);
void             frost_unsetenv(const char *variable);

/*
 * Precondition macros
 */
#ifndef MAX
#define MAX(a,b)    (a>b)?a:b
#endif

#ifndef MIN
#define MIN(a,b)    (a<b)?a:b
#endif

#define FROST_STMT_START    do
#define FROST_STMT_END      while (0)

#define frost_warn_if_fail(x)  FROST_STMT_START { if (!(x)) { printf ("%s:%d: assertion '%s' failed\n", __FILE__, __LINE__, #x); } } FROST_STMT_END
#define frost_return_if_fail(x)  FROST_STMT_START { if (!(x)) { printf ("%s:%d: assertion '%s' failed\n", __FILE__, __LINE__, #x); return; } } FROST_STMT_END
#define frost_return_val_if_fail(x,e)  FROST_STMT_START { if (!(x)) { printf ("%s:%d: assertion '%s' failed\n", __FILE__, __LINE__, #x); return (e); } } FROST_STMT_END

#define FROST_GNUC_PRETTY_FUNCTION
#define FROST_GNUC_UNUSED            __attribute__((__unused__))
#define FROST_BYTE_ORDER             FROST_LITTLE_ENDIAN
#define FROST_GNUC_NORETURN          __attribute__((__noreturn__))
#define FROST_SEARCHPATH_SEPARATOR_S ":"
#define FROST_SEARCHPATH_SEPARATOR   ':'
#define FROST_DIR_SEPARATOR          '/'
#define FROST_DIR_SEPARATOR_S        "/"
#define FROST_OS_UNIX
#define frost_pointer_TO_INT(ptr)   ((frost_int)(long) (ptr))
#define frost_pointer_TO_UINT(ptr)  ((frost_uint)(long) (ptr))
#define frost_int_TO_POINTER(v)     ((frost_pointer)(frost_long) (v))
#define frost_uint_TO_POINTER(v)    ((frost_pointer)(frost_ulong) (v))

#define FROST_UINT16_SWAP_LE_BE_CONSTANT(x) ((((frost_uint16) x) >> 8) | ((((frost_uint16) x) << 8)))

#define FROST_UINT16_SWAP_LE_BE(x) ((frost_uint16) (((frost_uint16) x) >> 8) | ((((frost_uint16)(x)) & 0xff) << 8))
#define FROST_UINT32_SWAP_LE_BE(x) ((frost_uint32) \
                   ( (((frost_uint32) (x)) << 24)| \
                 ((((frost_uint32) (x)) & 0xff0000) >> 8) | \
                         ((((frost_uint32) (x)) & 0xff00) << 8) | \
                     (((frost_uint32) (x)) >> 24)) )

#define FROST_UINT64_SWAP_LE_BE(x) ((frost_uint64) (((frost_uint64)(FROST_UINT32_SWAP_LE_BE(((frost_uint64)x) & 0xffffffff))) << 32) | \
                           FROST_UINT32_SWAP_LE_BE(((frost_uint64)x) >> 32))



#if FROST_BYTE_ORDER == FROST_LITTLE_ENDIAN
#   define FROST_UINT64_FROM_BE(x) FROST_UINT64_SWAP_LE_BE(x)
#   define FROST_UINT32_FROM_BE(x) FROST_UINT32_SWAP_LE_BE(x)
#   define FROST_UINT16_FROM_BE(x) FROST_UINT16_SWAP_LE_BE(x)
#   define FROST_UINT_FROM_BE(x)   FROST_UINT32_SWAP_LE_BE(x)
#   define FROST_UINT64_FROM_LE(x) (x)
#   define FROST_UINT32_FROM_LE(x) (x)
#   define FROST_UINT16_FROM_LE(x) (x)
#   define FROST_UINT_FROM_LE(x)   (x)
#   define FROST_UINT64_TO_BE(x)   FROST_UINT64_SWAP_LE_BE(x)
#   define FROST_UINT32_TO_BE(x)   FROST_UINT32_SWAP_LE_BE(x)
#   define FROST_UINT16_TO_BE(x)   FROST_UINT16_SWAP_LE_BE(x)
#   define FROST_UINT_TO_BE(x)     FROST_UINT32_SWAP_LE_BE(x)
#   define FROST_UINT64_TO_LE(x)   (x)
#   define FROST_UINT32_TO_LE(x)   (x)
#   define FROST_UINT16_TO_LE(x)   (x)
#   define FROST_UINT_TO_LE(x)     (x)
#else
#   define FROST_UINT64_FROM_BE(x) (x)
#   define FROST_UINT32_FROM_BE(x) (x)
#   define FROST_UINT16_FROM_BE(x) (x)
#   define FROST_UINT_FROM_BE(x)   (x)
#   define FROST_UINT64_FROM_LE(x) FROST_UINT64_SWAP_LE_BE(x)
#   define FROST_UINT32_FROM_LE(x) FROST_UINT32_SWAP_LE_BE(x)
#   define FROST_UINT16_FROM_LE(x) FROST_UINT16_SWAP_LE_BE(x)
#   define FROST_UINT_FROM_LE(x)   FROST_UINT32_SWAP_LE_BE(x)
#   define FROST_UINT64_TO_BE(x)   (x)
#   define FROST_UINT32_TO_BE(x)   (x)
#   define FROST_UINT16_TO_BE(x)   (x)
#   define FROST_UINT_TO_BE(x)     (x)
#   define FROST_UINT64_TO_LE(x)   FROST_UINT64_SWAP_LE_BE(x)
#   define FROST_UINT32_TO_LE(x)   FROST_UINT32_SWAP_LE_BE(x)
#   define FROST_UINT16_TO_LE(x)   FROST_UINT16_SWAP_LE_BE(x)
#   define FROST_UINT_TO_LE(x)     FROST_UINT32_SWAP_LE_BE(x)
#endif

#define FROST_INT64_FROM_BE(x)   (FROST_UINT64_TO_BE (x))
#define FROST_INT32_FROM_BE(x)   (FROST_UINT32_TO_BE (x))
#define FROST_INT16_FROM_BE(x)   (FROST_UINT16_TO_BE (x))
#define FROST_INT64_FROM_LE(x)   (FROST_UINT64_TO_LE (x))
#define FROST_INT32_FROM_LE(x)   (FROST_UINT32_TO_LE (x))
#define FROST_INT16_FROM_LE(x)   (FROST_UINT16_TO_LE (x))

#define SWAP16(v, endian) \
    if (endian == FROST_LITTLE_ENDIAN) { \
        v = FROST_UINT16_TO_LE (v); \
    } else if (endian == FROST_BIFROST_ENDIAN) { \
        v = FROST_UINT16_TO_BE (v); \
    }

#define SWAP32(v, endian) \
    if (endian == FROST_LITTLE_ENDIAN) { \
        v = FROST_UINT32_TO_LE (v); \
    } else if (endian == FROST_BIFROST_ENDIAN) { \
        v = FROST_UINT32_TO_BE (v); \
    }

/*
 * Hashtables
 */
typedef struct _FROSTHashTable FROSTHashTable;
typedef struct _FROSTHashTableIter FROSTHashTableIter;
typedef struct _Slot Slot;

/* Private, but needed for stack allocation */
struct _FROSTHashTableIter
{
    frost_pointer dummy [8];
};

struct _Slot {
    frost_pointer key;
    frost_pointer value;
    Slot    *next;
};


typedef void     (*FROSTFunc)          (frost_pointer data, frost_pointer user_data);
typedef frost_int     (*FROSTCompareFunc)   (frost_constpointer a, frost_constpointer b);
typedef frost_int     (*FROSTCompareDataFunc) (frost_constpointer a, frost_constpointer b, frost_pointer user_data);
typedef void     (*FROSTHFunc)         (frost_pointer key, frost_pointer value, frost_pointer user_data);
typedef frost_bool (*FROSTHRFunc)        (frost_pointer key, frost_pointer value, frost_pointer user_data);
typedef void     (*FROSTDestroyNotify) (frost_pointer data);
typedef frost_uint    (*FROSTHashFunc)      (frost_constpointer key);
typedef frost_bool (*FROSTEqualFunc)     (frost_constpointer a, frost_constpointer b);
typedef void     (*FROSTFreeFunc)      (frost_pointer       data);

struct _FROSTHashTable {
    FROSTHashFunc      hash_func;
    FROSTEqualFunc     key_equal_func;

    Slot **table;
    int   table_size;
    int   in_use;
    int   threshold;
    int   last_rehash;
    FROSTDestroyNotify value_destroy_func, key_destroy_func;
};

typedef struct {
    FROSTHashTable *ht;
    int slot_index;
    Slot *slot;
} Iter;

FROSTHashTable     *frost_hash_table_new             (FROSTHashFunc hash_func, FROSTEqualFunc key_equal_func);
FROSTHashTable     *frost_hash_table_new_full        (FROSTHashFunc hash_func, FROSTEqualFunc key_equal_func,
                          FROSTDestroyNotify key_destroy_func, FROSTDestroyNotify value_destroy_func);
void            frost_hash_table_insert_replace  (FROSTHashTable *hash, frost_pointer key, frost_pointer value, frost_bool replace);
frost_uint           frost_hash_table_size            (FROSTHashTable *hash);
frost_pointer        frost_hash_table_lookup          (FROSTHashTable *hash, frost_constpointer key);
frost_bool        frost_hash_table_lookup_extended (FROSTHashTable *hash, frost_constpointer key, frost_pointer *orifrost_key, frost_pointer *value);
void            frost_hash_table_foreach         (FROSTHashTable *hash, FROSTHFunc func, frost_pointer user_data);
frost_pointer        frost_hash_table_find            (FROSTHashTable *hash, FROSTHRFunc predicate, frost_pointer user_data);
frost_bool        frost_hash_table_remove          (FROSTHashTable *hash, frost_constpointer key);
void            frost_hash_table_remove_all      (FROSTHashTable *hash);
frost_uint           frost_hash_table_foreach_remove  (FROSTHashTable *hash, FROSTHRFunc func, frost_pointer user_data);
frost_uint           frost_hash_table_foreach_steal   (FROSTHashTable *hash, FROSTHRFunc func, frost_pointer user_data);
void            frost_hash_table_destroy         (FROSTHashTable *hash);
void            frost_hash_table_print_stats     (FROSTHashTable *table);

void            frost_hash_table_iter_init       (FROSTHashTableIter *iter, FROSTHashTable *hash_table);
frost_bool        frost_hash_table_iter_next       (FROSTHashTableIter *iter, frost_pointer *key, frost_pointer *value);

frost_uint           frost_spaced_primes_closest      (frost_uint x);

#define frost_hash_table_insert(h,k,v)    frost_hash_table_insert_replace ((h),(k),(v),frost_false)
#define frost_hash_table_replace(h,k,v)   frost_hash_table_insert_replace ((h),(k),(v),frost_true)

frost_bool frost_direct_equal (frost_constpointer v1, frost_constpointer v2);
frost_uint    frost_direct_hash  (frost_constpointer v1);
frost_bool frost_int_equal    (frost_constpointer v1, frost_constpointer v2);
frost_uint    frost_int_hash     (frost_constpointer v1);
frost_bool frost_str_equal    (frost_constpointer v1, frost_constpointer v2);
frost_uint    frost_str_hash     (frost_constpointer v1);

#ifdef __cplusplus
}
#endif


#endif /* FROST_COMMON_H_ */
