#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "libguile/_scm.h"
#include "libguile/eq.h"
#include "libguile/validate.h"
#include "libguile/numbers.h"
#include "libguile/srfi-60.h"
SCM_DEFINE (scm_srfi60_log2_binary_factors, "log2-binary-factors", 1, 0, 0,
(SCM n),
"Return a count of how many factors of 2 are present in @var{n}.\n"
"This is also the bit index of the lowest 1 bit in @var{n}. If\n"
"@var{n} is 0, the return is @math{-1}.\n"
"\n"
"@example\n"
"(log2-binary-factors 6) @result{} 1\n"
"(log2-binary-factors -8) @result{} 3\n"
"@end example")
#define FUNC_NAME s_scm_srfi60_log2_binary_factors
{
SCM ret = SCM_EOL;
if (SCM_I_INUMP (n))
{
long nn = SCM_I_INUM (n);
if (nn == 0)
return SCM_I_MAKINUM (-1);
nn = nn ^ (nn-1);
return scm_logcount (SCM_I_MAKINUM (nn >> 1));
}
else if (SCM_BIGP (n))
{
return SCM_I_MAKINUM (mpz_scan1 (SCM_I_BIG_MPZ (n), 0L));
}
else
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
return ret;
}
#undef FUNC_NAME
SCM_DEFINE (scm_srfi60_copy_bit, "copy-bit", 3, 0, 0,
(SCM index, SCM n, SCM newbit),
"Return @var{n} with the bit at @var{index} set according to\n"
"@var{newbit}. @var{newbit} should be @code{#t} to set the bit\n"
"to 1, or @code{#f} to set it to 0. Bits other than at\n"
"@var{index} are unchanged in the return.\n"
"\n"
"@example\n"
"(copy-bit 1 #b0101 #t) @result{} 7\n"
"@end example")
#define FUNC_NAME s_scm_srfi60_copy_bit
{
SCM r;
unsigned long ii;
int bb;
ii = scm_to_ulong (index);
bb = scm_to_bool (newbit);
if (SCM_I_INUMP (n))
{
long nn = SCM_I_INUM (n);
if (ii < SCM_LONG_BIT-1)
{
nn &= ~(1L << ii);
nn |= ((long) bb << ii);
return scm_from_long (nn);
}
else
{
if (bb == (nn < 0))
return n;
r = scm_i_long2big (nn);
goto big;
}
}
else if (SCM_BIGP (n))
{
if (bb == mpz_tstbit (SCM_I_BIG_MPZ (n), ii))
return n;
r = scm_i_clonebig (n, 1);
big:
if (bb)
mpz_setbit (SCM_I_BIG_MPZ (r), ii);
else
mpz_clrbit (SCM_I_BIG_MPZ (r), ii);
return scm_i_normbig (r);
}
else
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
}
#undef FUNC_NAME
SCM_DEFINE (scm_srfi60_rotate_bit_field, "rotate-bit-field", 4, 0, 0,
(SCM n, SCM count, SCM start, SCM end),
"Return @var{n} with the bit field from @var{start} (inclusive)\n"
"to @var{end} (exclusive) rotated upwards by @var{count} bits.\n"
"\n"
"@var{count} can be positive or negative, and it can be more\n"
"than the field width (it'll be reduced modulo the width).\n"
"\n"
"@example\n"
"(rotate-bit-field #b0110 2 1 4) @result{} #b1010\n"
"@end example")
#define FUNC_NAME s_scm_srfi60_rotate_bit_field
{
unsigned long ss = scm_to_ulong (start);
unsigned long ee = scm_to_ulong (end);
unsigned long ww, cc;
SCM_ASSERT_RANGE (3, end, (ee >= ss));
ww = ee - ss;
if (ww <= 1)
cc = 0;
else
cc = scm_to_ulong (scm_modulo (count, scm_difference (end, start)));
if (SCM_I_INUMP (n))
{
long nn = SCM_I_INUM (n);
if (ee <= SCM_LONG_BIT-1)
{
unsigned long unn = nn;
unsigned long below = unn & ((1UL << ss) - 1);
unsigned long above = unn & ~((1UL << ee) - 1);
unsigned long fmask = ((1UL << ww) - 1) << ss;
unsigned long ff = unn & fmask;
unsigned long uresult = (above
| ((ff << cc) & fmask)
| ((ff >> (ww-cc)) & fmask)
| below);
long result;
if (uresult > LONG_MAX)
result = -1 - (long) ~uresult;
else
result = (long) uresult;
return scm_from_long (result);
}
else
{
if (cc == 0)
return n;
n = scm_i_long2big (nn);
goto big;
}
}
else if (SCM_BIGP (n))
{
mpz_t tmp;
SCM r;
if (cc == 0)
return n;
big:
r = scm_i_ulong2big (0);
mpz_init (tmp);
mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (n), ee);
mpz_mul_2exp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), ee);
mpz_fdiv_q_2exp (tmp, SCM_I_BIG_MPZ (n), ss);
mpz_fdiv_r_2exp (tmp, tmp, ww - cc);
mpz_mul_2exp (tmp, tmp, ss + cc);
mpz_ior (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), tmp);
mpz_fdiv_q_2exp (tmp, SCM_I_BIG_MPZ (n), ee - cc);
mpz_fdiv_r_2exp (tmp, tmp, cc);
mpz_mul_2exp (tmp, tmp, ss);
mpz_ior (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), tmp);
mpz_fdiv_r_2exp (tmp, SCM_I_BIG_MPZ (n), ss);
mpz_ior (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), tmp);
mpz_clear (tmp);
return scm_i_normbig (r);
}
else
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
}
#undef FUNC_NAME
SCM_DEFINE (scm_srfi60_reverse_bit_field, "reverse-bit-field", 3, 0, 0,
(SCM n, SCM start, SCM end),
"Return @var{n} with the bits between @var{start} (inclusive) to\n"
"@var{end} (exclusive) reversed.\n"
"\n"
"@example\n"
"(reverse-bit-field #b101001 2 4) @result{} #b100101\n"
"@end example")
#define FUNC_NAME s_scm_srfi60_reverse_bit_field
{
long ss = scm_to_long (start);
long ee = scm_to_long (end);
long swaps = (ee - ss) / 2;
SCM b;
if (SCM_I_INUMP (n))
{
long nn = SCM_I_INUM (n);
if (ee <= SCM_LONG_BIT-1)
{
long smask = 1L << ss;
long emask = 1L << (ee-1);
for ( ; swaps > 0; swaps--)
{
long sbit = nn & smask;
long ebit = nn & emask;
nn ^= sbit ^ (ebit ? smask : 0)
^ ebit ^ (sbit ? emask : 0);
smask <<= 1;
emask >>= 1;
}
return scm_from_long (nn);
}
else
{
if (ee - ss <= 1)
return n;
b = scm_i_long2big (nn);
goto big;
}
}
else if (SCM_BIGP (n))
{
if (ee - ss <= 1)
return n;
b = scm_i_clonebig (n, 1);
big:
ee--;
for ( ; swaps > 0; swaps--)
{
int sbit = mpz_tstbit (SCM_I_BIG_MPZ (b), ss);
int ebit = mpz_tstbit (SCM_I_BIG_MPZ (b), ee);
if (sbit ^ ebit)
{
if (sbit)
{
mpz_clrbit (SCM_I_BIG_MPZ (b), ss);
mpz_setbit (SCM_I_BIG_MPZ (b), ee);
}
else
{
mpz_setbit (SCM_I_BIG_MPZ (b), ss);
mpz_clrbit (SCM_I_BIG_MPZ (b), ee);
}
}
ss++;
ee--;
}
return scm_i_normbig (b);
}
else
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
}
#undef FUNC_NAME
SCM_DEFINE (scm_srfi60_integer_to_list, "integer->list", 1, 1, 0,
(SCM n, SCM len),
"Return bits from @var{n} in the form of a list of @code{#t} for\n"
"1 and @code{#f} for 0. The least significant @var{len} bits\n"
"are returned, and the first list element is the most\n"
"significant of those bits. If @var{len} is not given, the\n"
"default is @code{(integer-length @var{n})} (@pxref{Bitwise\n"
"Operations}).\n"
"\n"
"@example\n"
"(integer->list 6) @result{} (#t #t #f)\n"
"(integer->list 1 4) @result{} (#f #f #f #t)\n"
"@end example")
#define FUNC_NAME s_scm_srfi60_integer_to_list
{
SCM ret = SCM_EOL;
unsigned long ll, i;
if (SCM_UNBNDP (len))
len = scm_integer_length (n);
ll = scm_to_ulong (len);
if (SCM_I_INUMP (n))
{
long nn = SCM_I_INUM (n);
for (i = 0; i < ll; i++)
{
unsigned long shift =
(i < ((unsigned long) SCM_LONG_BIT-1))
? i : ((unsigned long) SCM_LONG_BIT-1);
int bit = (nn >> shift) & 1;
ret = scm_cons (scm_from_bool (bit), ret);
}
}
else if (SCM_BIGP (n))
{
for (i = 0; i < ll; i++)
ret = scm_cons (scm_from_bool (mpz_tstbit (SCM_I_BIG_MPZ (n), i)),
ret);
scm_remember_upto_here_1 (n);
}
else
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
return ret;
}
#undef FUNC_NAME
SCM_DEFINE (scm_srfi60_list_to_integer, "list->integer", 1, 0, 0,
(SCM lst),
"Return an integer formed bitwise from the given @var{lst} list\n"
"of booleans. Each boolean is @code{#t} for a 1 and @code{#f}\n"
"for a 0. The first element becomes the most significant bit in\n"
"the return.\n"
"\n"
"@example\n"
"(list->integer '(#t #f #t #f)) @result{} 10\n"
"@end example")
#define FUNC_NAME s_scm_srfi60_list_to_integer
{
long len;
while (scm_is_pair (lst) && scm_is_false (SCM_CAR (lst)))
lst = SCM_CDR (lst);
SCM_VALIDATE_LIST_COPYLEN (SCM_ARG1, lst, len);
if (len <= SCM_I_FIXNUM_BIT - 1)
{
long n = 0;
while (scm_is_pair (lst))
{
n <<= 1;
if (! scm_is_false (SCM_CAR (lst)))
n++;
lst = SCM_CDR (lst);
}
return SCM_I_MAKINUM (n);
}
else
{
SCM n = scm_i_ulong2big (0);
while (scm_is_pair (lst))
{
len--;
if (! scm_is_false (SCM_CAR (lst)))
mpz_setbit (SCM_I_BIG_MPZ (n), len);
lst = SCM_CDR (lst);
}
return n;
}
}
#undef FUNC_NAME
SCM_REGISTER_PROC (s_srfi60_booleans_to_integer, "booleans->integer", 0, 0, 1, scm_srfi60_list_to_integer);
void
scm_register_srfi_60 (void)
{
scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
"scm_init_srfi_60",
(scm_t_extension_init_func)scm_init_srfi_60, NULL);
}
void
scm_init_srfi_60 (void)
{
#ifndef SCM_MAGIC_SNARFER
#include "libguile/srfi-60.x"
#endif
}