/*
 * $Id: sets.c 23771 2007-12-12 02:29:12Z petdance $
 * Copyright (C) 2002-2007, The Perl Foundation.
 */

/*

=head1 NAME

compilers/imcc/sets.c

=head1 DESCRIPTION

RT#48264

=head2 Functions

=over 4

=cut

*/

#include "imc.h"
#include "sets.h"

/* HEADERIZER HFILE: compilers/imcc/sets.h */

/* XXX */
#define fatal(e, s1, s2) do { \
    fprintf(stderr, "%s: %s", s1, s2); \
    exit(e); \
} while (0)

#define NUM_BYTES(length)    ((length / 8) + 1)
#define BYTE_IN_SET(element) (element >> 3)
#define BIT_IN_BYTE(element) (1 << (element & 7))

/*

=item C<PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set*
set_make(int length)>

RT#48260: Not yet documented!!!

=cut

*/

PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set*
set_make(int length)
{
    Set * const s = mem_allocate_typed(Set);
    s->length     = length;
    s->bmp        = (unsigned char *)mem_sys_allocate_zeroed(NUM_BYTES(length));
    return s;
}

/*

=item C<PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set*
set_make_full(int length)>

RT#48260: Not yet documented!!!

=cut

*/

PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set*
set_make_full(int length)
{
    Set * const s   = set_make(length);
    const int bytes = NUM_BYTES(length);

    if (bytes)
        memset(s->bmp, 0xff, bytes);

    return s;
}

/*

=item C<void
set_free(NOTNULL(Set *s))>

RT#48260: Not yet documented!!!

=cut

*/

void
set_free(NOTNULL(Set *s))
{
    if (s->bmp)
        mem_sys_free(s->bmp);
    mem_sys_free(s);
}

/*

=item C<void
set_clear(NOTNULL(Set *s))>

RT#48260: Not yet documented!!!

=cut

*/

void
set_clear(NOTNULL(Set *s))
{
    memset(s->bmp, 0, NUM_BYTES(s->length));
}

/*

=item C<PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set*
set_copy(NOTNULL(Set *s))>

RT#48260: Not yet documented!!!

=cut

*/

PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set*
set_copy(NOTNULL(Set *s))
{
    Set * const d = set_make(s->length);

    memcpy(d->bmp, s->bmp, NUM_BYTES(d->length));
    return d;
}

/*

=item C<int
set_equal(ARGIN(const Set *s1), ARGIN(const Set *s2))>

RT#48260: Not yet documented!!!

=cut

*/

int
set_equal(ARGIN(const Set *s1), ARGIN(const Set *s2))
{
    int mask;
    const int bytes = s1->length / 8;

    if (s1->length != s2->length) {
        fatal(1, "set_equal", "Sets don't have the same length\n");
    }

    if (bytes)
        if (memcmp(s1->bmp, s2->bmp, bytes) != 0)
            return 0;

    if (s1->length % 8 == 0)
        return 1;

    mask = (1 << (s1->length % 8)) - 1;

    if ((s1->bmp[bytes] & mask) != (s2->bmp[bytes] & mask))
        return 0;

    return 1;
}

/*

=item C<void
set_add(NOTNULL(Set *s), int element)>

RT#48260: Not yet documented!!!

=cut

*/

void
set_add(NOTNULL(Set *s), int element)
{
    const int elem_byte_in_set = BYTE_IN_SET(element);
    const int bytes_in_set     = BYTE_IN_SET(s->length);

    if (bytes_in_set < elem_byte_in_set) {
        s->bmp = (unsigned char *)mem_sys_realloc_zeroed(s->bmp,
            NUM_BYTES(element), NUM_BYTES(s->length));
        s->length += 8;
    }

    s->bmp[elem_byte_in_set] |= BIT_IN_BYTE(element);
}

/*

=item C<PARROT_WARN_UNUSED_RESULT
PARROT_PURE_FUNCTION
int
set_first_zero(ARGIN(const Set *s))>

RT#48260: Not yet documented!!!

=cut

*/

PARROT_WARN_UNUSED_RESULT
PARROT_PURE_FUNCTION
int
set_first_zero(ARGIN(const Set *s))
{
    int i, j;

    for (i = 0; i < NUM_BYTES(s->length); ++i) {
        int set_byte = s->bmp[i];
        if (set_byte == 0xFF)
            continue;

        for (j = 0; j < 8; ++j) {
            int element = i * 8 + j;
            if (!set_contains(s, element))
                return element;
        }
    }

    return s->length;
}

/*

=item C<PARROT_WARN_UNUSED_RESULT
PARROT_PURE_FUNCTION
int
set_contains(ARGIN(const Set *s), int element)>

RT#48260: Not yet documented!!!

=cut

*/

PARROT_WARN_UNUSED_RESULT
PARROT_PURE_FUNCTION
int
set_contains(ARGIN(const Set *s), int element)
{
    /* workaround for another lcc bug.. */
    const int byte_in_set = element >> 3;
    const int pos_in_byte = BIT_IN_BYTE(element);

    if (element > s->length)
        return 0;

    return s->bmp[byte_in_set] & pos_in_byte;
}

/*

=item C<PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set *
set_union(ARGIN(const Set *s1), ARGIN(const Set *s2))>

RT#48260: Not yet documented!!!

=cut

*/

PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set *
set_union(ARGIN(const Set *s1), ARGIN(const Set *s2))
{
    int i;
    Set * const s = set_make(s1->length);

    if (s1->length != s2->length) {
        fatal(1, "set_union", "Sets don't have the same length\n");
    }

    for (i=0; i < BYTE_IN_SET(s1->length); i++) {
        s->bmp[i] = s1->bmp[i] | s2->bmp[i];
    }

    return s;
}

/*

=item C<PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set *
set_intersec(ARGIN(const Set *s1), ARGIN(const Set *s2))>

RT#48260: Not yet documented!!!

=cut

*/

PARROT_MALLOC
PARROT_CANNOT_RETURN_NULL
Set *
set_intersec(ARGIN(const Set *s1), ARGIN(const Set *s2))
{
    int i;
    Set * const s = set_make(s1->length);

    if (s1->length != s2->length) {
        fatal(1, "set_intersec", "Sets don't have the same length\n");
    }

    for (i=0; i < BYTE_IN_SET(s1->length); i++) {
        s->bmp[i] = s1->bmp[i] & s2->bmp[i];
    }

    return s;
}

/*

=item C<void
set_intersec_inplace(NOTNULL(Set *s1), ARGIN(const Set *s2))>

RT#48260: Not yet documented!!!

=cut

*/

void
set_intersec_inplace(NOTNULL(Set *s1), ARGIN(const Set *s2))
{
    int i;

    if (s1->length != s2->length) {
        fatal(1, "set_intersec_inplace", "Sets don't have the same length\n");
    }

    for (i=0; i < BYTE_IN_SET(s1->length); i++) {
        s1->bmp[i] &= s2->bmp[i];
    }
}

/*

=back

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */


syntax highlighted by Code2HTML, v. 0.9.1