Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

#include <stdio.h>
#include <stdlib.h>

#include "mhmt-types.h"
#include "mhmt-optimal.h"


// allocate place for optimal chain building amd initialize it
struct optchain * make_optch(ULONG actual_len)
{
        struct optchain * optch;

        ULONG i;

        // we allocate length+1 because all codes at the end of input stream will point
        // to the length+1 place. Also we'll start reversing from length+1 position in optch array
        optch = (struct optchain *)malloc( (actual_len+1)*sizeof(struct optchain) );

        if( optch )
        {
                optch[0].code.length = 1; // 1st byte is always copied 'as-is', however, this is just filler,
                optch[0].code.disp   = 0; // not accounted elsewhere

                // init prices to absolute maximum for optimal chain build-up
                optch[0].price = 0;
                optch[1].price = 8;
                for(i=2;i<(actual_len+1);i++)
                        optch[i].price = 0xFFFFFFFF;
        }

        return optch;
}

struct optch_hst ** make_optch_hst(ULONG actual_len)
{
        struct optch_hst ** optch_bunch;

        ULONG i,j;


        optch_bunch = (struct optch_hst **)calloc( 8, sizeof(struct optch_hst *) );

        if( optch_bunch )
        {
                for(i=0;i<8;i++)
                {
                        optch_bunch[i] = (struct optch_hst *)malloc( (actual_len+1)*sizeof(struct optch_hst) );
                        if( !optch_bunch[i] )
                        { // error recovery (free allocated mem)
                                free_optch_hst(optch_bunch);
                                return NULL;
                        }
                }

                for(i=0;i<8;i++)
                {
                        for(j=0;j<(actual_len+1);j++)
                        {
                                optch_bunch[i][j].code.length = 0;
                                optch_bunch[i][j].code.disp   = 0;
                                optch_bunch[i][j].path        = (-1);
                                optch_bunch[i][j].price       = 0xFFFFFFFF;
                        }
                }

                optch_bunch[0][0].code.length = 1;
                optch_bunch[0][0].code.disp   = 0;

                optch_bunch[0][0].price = 0;
                optch_bunch[0][1].price = 8;
               
                optch_bunch[0][0].path = 0;
                optch_bunch[0][1].path = 0;
        }

        return optch_bunch;
}




// free optchain array
void free_optch(struct optchain * optch)
{
        if( optch )
                free( optch );
}

void free_optch_hst(struct optch_hst ** optch)
{
        ULONG i;

        if( optch )
        {
                for(i=0;i<8;i++)
                {
                        if( optch[i] )
                                free( optch[i] );
                }
                free( optch );
        }
}





// update prices at the position given all lzcodes.
// it also needs pointer to the function that calculates bit length of given LZ code
void update_optch(ULONG position, struct lzcode * codes, ULONG (*get_lz_price)(OFFSET position, struct lzcode * lzcode), struct optchain * optch)
{
        ULONG codepos;
        ULONG bitlen;
        ULONG newpos;
        LONG len;

        for( codepos = 0; len=codes[codepos].length; codepos++ ) // loop through all existing lz codes
        {
                bitlen = (*get_lz_price)(position, &codes[codepos]); // get bit length of given lz code
                if( !bitlen )
                {
                        printf("mhmt-optimal.c: update_optch() found zero bitlength of lz code. Fatal error.\n");
                        exit(1);
                }
                else
                {
                        if( len<0 ) len=(-len); // deal with negative lengths (special markers)

                        newpos = position + len; // look where current lz code points to and take from there old price reaching that location

                        if( optch[newpos].price > bitlen + optch[position].price ) // if oldprice is worse than with current lz code
                        {
                                optch[newpos].price = bitlen + optch[position].price;
                                optch[newpos].code  = codes[codepos];
                        }
                }
        }
}






// reverses optimal chain making it ready for scanning (fetching optimal chain)
//
void reverse_optch(struct optchain * optch, ULONG actual_len)
{
        struct lzcode curr, temp;
        ULONG position;
        LONG len;

        position = actual_len;

        temp = optch[position].code;

        while(position>1)
        {
                len = temp.length;
                if( len<0 ) len=(-len);

                position -= len;

                curr = temp;

                temp = optch[position].code;
                optch[position].code = curr;
        }
}