#include <stdint.h>
#include <stdlib.h>

/** Struktura predstavujici tabulist */
struct tabulist_s {
        uint_fast16_t delka;
        uint_fast16_t max_element;
        uint_fast16_t pozice;
        uint_fast16_t *list;
        uint64_t mapa[];
};

/** Konstruktor - vytvori novy tabulist
 * @param delka - delka tabulist
 * @param max_element - max. hodnota elementu v tabulistu. Hodnot vkládané do tabulistu musí být z {1, 2, ... max_element }
 * @return nový tabulist
 */
struct tabulist_s *tabulist_new(int delka, int max_element)
{
        struct tabulist_s *tabulist;
        tabulist = (struct tabulist_s *)calloc(1,sizeof(uint_fast16_t)*delka + sizeof(uint64_t)*(1 + ((max_element+1) >> 6)));
        tabulist->list = (uint_fast16_t *)calloc(sizeof(uint_fast16_t), delka);
        tabulist->list[0] = 0;
        tabulist->delka = delka;
        tabulist->max_element = max_element;
        return tabulist;
}

/** Ověří zda tabulist obsahuje element
 * @return 0 pokud neobsahuje, jinak nenulovou hodnotu
 */
int tabulist_obsahuje(const struct tabulist_s* const tabulist, int element)
{
        return tabulist->mapa[ element >> 6 ] & ( 1 << (element & 0x3F ) );
}

/** Vypíše tabulist na stdout */
void tabulist_vypis(const struct tabulist_s* const tabulist)
{
        int i;
        for( i = tabulist->pozice; i < tabulist->delka; i++ )
                printf("%d ", tabulist->list[i]);
        for( i = 0; i < tabulist->pozice; i++ )
                printf("%d ", tabulist->list[i]);
        printf("\n");
}

/** Vloží element do tabulistu */
void tabulist_vloz(struct tabulist_s* const tabulist, int element)
{
        if( tabulist_obsahuje(tabulist, element) ){
                uint_fast16_t i;
                for( i = 0; i < tabulist->delka; i++ )
                        if( tabulist->list[i] == element ){ tabulist->list[i] = 0; break; }
        }
        tabulist->mapa[ tabulist->list[ tabulist->pozice ] >> 6 ] &=
                ~( 1 << (tabulist->list[ tabulist->pozice ] & 0x3F ) );
        tabulist->mapa[ element >> 6 ] |= ( 1 << (element & 0x3F ) );
        tabulist->list[ tabulist->pozice ] = element;
        if( ++tabulist->pozice >= tabulist->delka ) tabulist->pozice = 0;
}
                
/** Vyprázdní tabulist (stejné jako smazání a vytvoření nového tabulistu) */
void tabulist_vyprazdni( struct tabulist_s * const tabulist )
{
        memset( tabulist->mapa, 0, sizeof(uint64_t) * (1+ ((tabulist->max_element + 1) >> 6)) );
        memset( tabulist->list, 0, sizeof(uint_fast16_t) * tabulist->delka  );
        tabulist->pozice = 0;
}

/** Destruktor */
void tabulist_znic( struct tabulist_s *tabulist )
{
        free( tabulist->list );
        free( tabulist );
}