#include #include #include #include #include #include #include "nmglobal.h" #include "nbench1.h" /************************ ** HUFFMAN COMPRESSION ** ************************/ /* ** DEFINES */ #define EXCLUDED 32000L /* Big positive value */ /* ** TYPEDEFS */ typedef struct { unsigned char c; /* Byte value */ float freq; /* Frequency */ int parent; /* Parent node */ int left; /* Left pointer = 0 */ int right; /* Right pointer = 1 */ } huff_node; /* ** GLOBALS */ static huff_node *hufftree; /* The huffman tree */ static long plaintextlen; /* Length of plaintext */ /* ** PROTOTYPES */ static void create_text_line(char *dt,long nchars); static void create_text_block(char *tb, unsigned long tblen, unsigned short maxlinlen); static unsigned long DoHuffIteration(char *plaintext, char *comparray, char *decomparray, unsigned long arraysize, unsigned long nloops, huff_node *hufftree); static void SetCompBit(uint8_t *comparray, uint32_t bitoffset, char bitchar); static int GetCompBit(uint8_t *comparray, uint32_t bitoffset); /* ** Word catalog */ #define WORDCATSIZE 50 char *wordcatarray[WORDCATSIZE] = { /* FIXME: const? */ "Hello", "He", "Him", "the", "this", "that", "though", "rough", "cough", "obviously", "But", "but", "bye", "begin", "beginning", "beginnings", "of", "our", "ourselves", "yourselves", "to", "together", "togetherness", "from", "either", "I", "A", "return", "However", "that", "example", "yet", "quickly", "all", "if", "were", "includes", "always", "never", "not", "small", "returns", "set", "basic", "Entered", "with", "used", "shown", "you", "know" }; /************** ** DoHuffman ** *************** ** Execute a huffman compression on a block of plaintext. ** Note that (as with IDEA encryption) an iteration of the ** Huffman test includes a compression AND a decompression. ** Also, the compression cycle includes building the ** Huffman tree. */ void DoHuffman(void) { HuffStruct *lochuffstruct; /* Loc pointer to global data */ char *context; int systemerror; unsigned long accumtime; double iterations; char *comparray = NULL; char *decomparray = NULL; char *plaintext = NULL; /* ** Link to global data */ lochuffstruct=&global_huffstruct; /* ** Set error context. */ context="CPU:Huffman"; /* ** Allocate memory for the plaintext and the compressed text. ** We'll be really pessimistic here, and allocate equal amounts ** for both (though we know...well, we PRESUME) the compressed ** stuff will take less than the plain stuff. ** Also note that we'll build a 3rd buffer to decompress ** into, and we preallocate space for the huffman tree. ** (We presume that the Huffman tree will grow no larger ** than 512 bytes. This is actually a super-conservative ** estimate...but, who cares?) */ plaintext = malloc(lochuffstruct->arraysize); if (!plaintext) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); exit(1); } comparray = malloc(lochuffstruct->arraysize); if (!comparray) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plaintext); exit(1); /* FIXME: do I need exits here? */ } decomparray = malloc(lochuffstruct->arraysize); if (!decomparray) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plaintext); free(comparray); exit(1); } hufftree = malloc(sizeof(huff_node) * 512); if (!hufftree) { fprintf(stderr, "Error in %s, could not allocate memory. Exitting...\n", context); free(plaintext); free(comparray); free(decomparray); exit(1); } /* ** Build the plaintext buffer. Since we want this to ** actually be able to compress, we'll use the ** wordcatalog to build the plaintext stuff. */ /* ** Reset random number generator so things repeat. ** added by Uwe F. Mayer */ randnum((int32_t)13); create_text_block(plaintext,lochuffstruct->arraysize-1,(unsigned short)500); plaintext[lochuffstruct->arraysize-1L]='\0'; plaintextlen=lochuffstruct->arraysize; /* ** See if we need to perform self adjustment loop. */ if(lochuffstruct->adjust==0) { /* ** Do self-adjustment. This involves initializing the ** # of loops and increasing the loop count until we ** get a number of loops that we can use. */ for(lochuffstruct->loops=100L; lochuffstruct->loopsloops+=10L) if(DoHuffIteration(plaintext, comparray, decomparray, lochuffstruct->arraysize, lochuffstruct->loops, hufftree)>global_min_ticks) break; } /* ** All's well if we get here. Do the test. */ accumtime=0L; iterations=(double)0.0; do { accumtime+=DoHuffIteration(plaintext, comparray, decomparray, lochuffstruct->arraysize, lochuffstruct->loops, hufftree); iterations+=(double)lochuffstruct->loops; } while(TicksToSecs(accumtime)request_secs); /* ** Clean up, calculate results, and go home. Be sure to ** show that we don't have to rerun adjustment code. */ free(plaintext); free(comparray); free(decomparray); free(hufftree); lochuffstruct->iterspersec=iterations / TicksToFracSecs(accumtime); if(lochuffstruct->adjust==0) lochuffstruct->adjust=1; } /********************* ** create_text_line ** ********************** ** Create a random line of text, stored at *dt. The line may be ** no more than nchars long. */ static void create_text_line(char *dt, long nchars) { long charssofar; /* # of characters so far */ long tomove; /* # of characters to move */ char myword[40]; /* Local buffer for words */ char *wordptr; /* Pointer to word from catalog */ charssofar=0; do { /* ** Grab a random word from the wordcatalog */ /* wordptr=wordcatarray[abs_randwc((long)WORDCATSIZE)];*/ wordptr=wordcatarray[abs_randwc((int32_t)WORDCATSIZE)]; memmove(myword, wordptr, strlen(wordptr) + 1); /* ** Append a blank. */ tomove=strlen(myword)+1; myword[tomove-1]=' '; /* ** See how long it is. If its length+charssofar > nchars, we have ** to trim it. */ if((tomove+charssofar)>nchars) tomove=nchars-charssofar; /* ** Attach the word to the current line. Increment counter. */ memmove(dt, myword, tomove); charssofar+=tomove; dt+=tomove; /* ** If we're done, bail out. Otherwise, go get another word. */ } while(charssofartblen) linelen=tblen-bytessofar; if(linelen>1) { create_text_line(tb,linelen); } tb+=linelen-1; /* Add the carriage return */ *tb++='\n'; bytessofar+=linelen; } while(bytessofar>3; bitnumb=bitoffset % 8; /* ** Set or clear */ if(bitchar=='1') comparray[byteoffset]|=(1<>3; bitnumb=bitoffset % 8; /* ** Fetch */ return((1<