#ifndef _lib_binstr_
#define _lib_binstr_ 1

/* __func__ is not defined in pre C99 so provide fallback */
#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
#  define __func__ __FUNCTION__
# else
#  define __func__ "<unknown>"
# endif
#endif

#if defined(__LP64__) || defined(_LP64)
# define BUILD_64   1
#endif

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  /* for uintX_t definitions */
#include <string.h>  /* for memcpy              */
#include <limits.h>  /* for CHAR_BIT            */

/* CHAR_BIT */
#ifndef CHAR_BIT
#define CHAR_BIT  8
#endif  /* CHAR_BIT */

/* 23 bits of float fractional data */
#define I2F_FRAC_BITS       23
#define I2F_MASK ((1 << I2F_FRAC_BITS) - 1)

/* return binary representation of x - static return */
char *binstr_8  (uint8_t x);
char *binstr_16 (uint16_t x);
char *binstr_32 (uint32_t x);
char *binstr_64 (uint64_t x);

/* return binary representation of x - dynamically allocated return */
char *binstr_8d  (uint8_t x);
char *binstr_16d (uint16_t x);
char *binstr_32d (uint32_t x);
char *binstr_64d (uint64_t x);

/* Function removes leading 0's from binary string
   returns pointer to MSB, otherwise returns NULL */
char *bin_nopad (char *s);

/* format string 's' into 'szgrp' groups separated by 'sep' */
char *binstr_sep (char *s, const size_t szgrp, char *sep);

/* return binary representation of x, in groups of szgrp bits, using separator sep */
char *fmtbinstr_8  (uint8_t x, const size_t szgrp, char *sep);
char *fmtbinstr_16 (uint16_t x, const size_t szgrp, char *sep);
char *fmtbinstr_32 (uint32_t x, const size_t szgrp, char *sep);
char *fmtbinstr_64 (uint64_t x, const size_t szgrp, char *sep);

/* functions for conversion of numbers to IEEE 754 format */

/* get most significant bit MSB */
inline int getmsb (uint64_t x);
/* get least significant bit LSB */
inline int getlsb (uint64_t x);
/* get number of 1's in binary number (population - pop)*/
int getn1s (unsigned x);
/* count leading zeros passing value and sizeof (uintX_t) */
int nlz (uint64_t x, unsigned szost);
/* count trailing zeros (any storage) */
int ntz (uint64_t x);

/* change sign for given value, x => -x, -x => x */
int chs (uint64_t x);

/* rotate left and rotate right 32-bit functions */
inline uint32_t rotl    (uint32_t value, int shift);
inline uint32_t rotr    (uint32_t value, int shift);
/* special case rotate functions */
inline uint8_t  rotl_8  (uint8_t  x, int shift);
inline uint8_t  rotr_8  (uint8_t  x, int shift);
inline uint16_t rotl_16 (uint16_t x, int shift);
inline uint16_t rotr_16 (uint16_t x, int shift);
inline uint64_t rotl_64 (uint64_t x, int shift);
inline uint64_t rotr_64 (uint64_t x, int shift);

/* IEEE 754 functions */
uint32_t u2ieee (uint32_t x);
uint32_t i2ieee (int32_t x);
double ieee32dbl (int val);

/* swap macro & type functions */
#define swap(x,y) do \
   { unsigned char swap_temp[sizeof(x) == sizeof (y) ? (signed)sizeof (x) : -1]; \
     memcpy (swap_temp,&y,sizeof (x)); \
     memcpy (&y,&x,       sizeof (x)); \
     memcpy (&x,swap_temp,sizeof (x)); \
    } while (0)

inline void swapi (int *a, int *b);
inline void swapu (unsigned int *a, unsigned int *b);
inline void swapl (long *a, long *b);
inline void swapf (float *a, float *b);
inline void swapd (double *a, double *b);
inline void swapc (char *a, char *b);

/* return minimum integer storage size based on msb */
inline int
bit_fldsz (unsigned long val);

/* bit functions */
inline void bit_setc    (uint8_t *bf, int n);
inline void bit_set     (uint64_t *bf, int n);
inline void bit_clearc  (uint8_t *bf, int n);
inline void bit_clear   (uint64_t *bf, int n);
inline void bit_togglec (uint8_t *bf, int n);
inline void bit_toggle  (uint64_t *bf, int n);

/* (bit == 1) ? return 1 : 0, on error return -1 */
inline int bit_isset (unsigned long bf, int n);

/* (bit == 1) ? return bitvaule : 0, on error return -1,
   loop to retrieve all set bits from bitfield/bitarray */
inline int bit_value (unsigned long bf, int n);

#endif /* _lib_binstr_ */