#ifndef __mpint_h
#define __mpint_h

#include <stdint.h>
#include <sys/types.h>
#include <assert.h>

#if !defined(MP_API)
# define MP_API
#endif

#if !defined(MP_INL)
# define MP_INL	static inline
#endif

typedef	uint32_t mp_digit_t;
typedef	uint64_t mp_digit2_t;
typedef	size_t	 mp_size_t;

typedef struct
{
  mp_size_t      width;
  mp_digit_t	*bits;
} mp_t;

#define	MP_INITIALISER	{ 0, 0 }

#define _mp_ok(MP)	(((MP)->bits && (MP)->width) || (!(MP)->bits && !(MP)->width))

#if !defined(MP_NO_DECLS)

MP_API mp_t	  *mp_clear(mp_t *mp);
MP_API mp_t	  *mp_copy(mp_t *dst, mp_t *src);
MP_API mp_digit_t  mp_digitAtPut(mp_t *mp, mp_size_t index, mp_digit_t value);
MP_API mp_t	  *mp_normalise(mp_t *mp);
MP_API int	   mp_cmp(mp_t *a, mp_t *b);
MP_API mp_t	  *mp_neg(mp_t *mp);
MP_API mp_t	  *mp_not(mp_t *mp);
MP_API mp_t	  *mp_and(mp_t *r, mp_t *a);
MP_API mp_t	  *mp_or(mp_t *r, mp_t *a);
MP_API mp_t	  *mp_xor(mp_t *r, mp_t *a);
MP_API mp_t	  *mp_shiftl(mp_t *mp, mp_size_t n);
MP_API mp_t	  *mp_shiftr(mp_t *mp, mp_size_t n);
MP_API mp_t	  *mp_add(mp_t *r, mp_t *a);
MP_API mp_t	  *mp_add_d(mp_t *r, mp_digit_t d);
MP_API mp_digit_t  mp_sub(mp_t *r, mp_t *a);
MP_API mp_digit_t  mp_sub_d(mp_t *r, mp_digit_t d);
MP_API mp_digit_t  mp_subf_d(mp_t *r, mp_digit_t d);
MP_API mp_t	  *mp_mul(mp_t *r, mp_t *a);
MP_API mp_t	  *mp_mul_d(mp_t *r, mp_digit_t n);
MP_API mp_t	  *mp_div(mp_t *quo, mp_t *rem, mp_t *dend, mp_t *dsor);
MP_API mp_digit_t  mp_div_d(mp_t *quo, mp_digit_t n);
MP_API char	  *mp_cvt(mp_t *mp, int base);

#endif

MP_INL mp_digit_t mp_digitAt(mp_t *mp, mp_size_t index)
{
  assert(_mp_ok(mp));
  return index < mp->width ? mp->bits[index] : 0;
}

MP_INL int mp_zerop(mp_t *mp)
{					assert(_mp_ok(mp));
  return !mp->width;
}

MP_INL mp_t *mp_shift(mp_t *mp, int n)
{
  return (n > 0) ? mp_shiftl(mp,  n) : mp_shiftr(mp, -n);
}

#endif /* __mpint_h */

