/***********************************************************************1* *2* This software is part of the ast package *3* Copyright (c) 2003-2011 AT&T Intellectual Property *4* and is licensed under the *5* Eclipse Public License, Version 1.0 *6* by AT&T Intellectual Property *7* *8* A copy of the License is available at *9* http://www.eclipse.org/org/documents/epl-v10.html *10* (with md5 checksum b35adb5213ca9657e911e9befb180842) *11* *12* Information and Software Systems Research *13* AT&T Research *14* Florham Park NJ *15* *16* Phong Vo <[email protected]> *17* *18***********************************************************************/19#include "vchhdr.h"2021/* Compute the code lengths for symbols based on their frequencies.22** This uses a linear-time algorithm after frequency sorting.23** Frequencies are scaled to be <= VCH_MAXWEIGHT so that max code24** length will be < VCH_MAXLENGTH.25**26** Written by Kiem-Phong Vo27*/2829#define VCH_MAXWEIGHT 2178308.0 /* fibonacci(32)-1 */30#define VCH_MAXLENGHTH 32 /* max length of any code */3132/* node in a kind-of-flattened Huffman tree */33typedef struct _vchtree_s34{ ssize_t freq; /* frequency of a symbol */35struct _vchtree_s* next; /* link for the sorted lists */36struct _vchtree_s* link; /* subtree linkage */37} Vchtree_t;3839/* sort by frequencies */40#if __STD_C41static int huffcmp(Void_t* one, Void_t* two, Void_t* disc)42#else43static int huffcmp(one, two, disc)44Void_t* one;45Void_t* two;46Void_t* disc;47#endif48{49int d;50Vchtree_t *o = *((Vchtree_t**)one);51Vchtree_t *t = *((Vchtree_t**)two);5253if((d = o->freq - t->freq) != 0 )54return d;55else return o < t ? -1 : o == t ? 0 : 1;56}5758#if __STD_C59ssize_t vchsize(ssize_t nsym, ssize_t* freq, ssize_t* size, int* runb)60#else61ssize_t vchsize(nsym, freq, size, runb)62ssize_t nsym; /* alphabet size */63ssize_t* freq; /* code frequencies */64ssize_t* size; /* computed code sizes */65int* runb; /* the run byte if any */66#endif67{68ssize_t k, c, notz, max, min;69Vchtree_t *tree, **sort;70Vchtree_t *f, *s, *p, *list, *tail, *head;7172if(!(tree = (Vchtree_t*)malloc(nsym*sizeof(Vchtree_t))) ||73!(sort = (Vchtree_t**)malloc(nsym*sizeof(Vchtree_t*))) )74return -1;7576/* construct list of elements with non-zero weights */77notz = 0;78max = min = freq[c = 0];79for(k = 0, f = tree; k < nsym; ++k, ++f, ++c)80{ size[c] = 0;8182f->next = f->link = NIL(Vchtree_t*);83if((f->freq = freq[c]) == 0 )84continue;8586if(min > f->freq)87min = f->freq;88else if(max < f->freq)89max = f->freq;9091sort[notz++] = f;92}9394if(runb)95*runb = -1;96if(notz <= 1) /* no Huffman code needed */97{ if(notz == 1 && runb)98*runb = (int)(sort[0]-tree);99free(tree);100free(sort);101return 0;102}103104/* scale to bound max # of bits for a code */105if((max -= min) > VCH_MAXWEIGHT)106for(k = 0; k < notz; ++k)107sort[k]->freq = (sort[k]->freq - min)*(VCH_MAXWEIGHT/max) + 1;108109/* build linked list sorted by frequencies */110vcqsort(sort, notz, sizeof(Vchtree_t*), huffcmp, 0);111for(f = sort[k = 0]; f != NIL(Vchtree_t*); f = f->next)112{ f->link = f; /* nodes in each subtree are kept in a circular list */113f->next = (k += 1) < notz ? sort[k] : NIL(Vchtree_t*);114}115116/* linear-time construction of a Huffman tree */117for(head = tail = NIL(Vchtree_t*), list = sort[0];; )118{ /* The invariant (I) needed at this point is this:119** 0. The lists "list" and "head" are sorted by frequency.120** 1. list and list->next are not NULL;121** 2. head == NULL or head->freq >= list->next->freq122** 3. tail == NULL or list->freq+list->next->freq >= tail->freq.123** Then, list and list->next can be merged into a subtree.124*/125f = list; s = list->next; list = s->next;126127/* the difference in depths of s and f will be fixed from now on */128size[s-tree] -= size[f-tree];129s->next = f; /* final_depth(s) = final_depth(f) + above difference */130131/* tree depth for subtree represented by f increases by 1 */132size[f-tree] += 1;133134/* merge subtrees, ie, link the two circular lists */135f->freq += s->freq;136p = f->link; f->link = s->link; s->link = p;137138/* move f to the list of merged pairs */139tail = head ? (tail->next = f) : (head = f);140tail->next = NIL(Vchtree_t*);141142if(list)143{ if(list->next && list->next->freq <= head->freq)144continue; /* invariant (I) satisfied, merge them */145146/* find the segment in "head" movable to start of list */147for(p = NIL(Vchtree_t*), f = head; f; p = f, f = f->next)148if(f->freq > list->freq)149break;150151/* going back to top of loop, so we need invariant (I).152** I.0, I.1 and I.2 will clearly be true after below move.153** Now observe that tail->freq <= 2*head->freq and154** tail->freq <= 2*list->freq. This gives I.3 in all cases.155*/156if(p)157{ p->next = list;158list = head;159}160else161{ f = head->next;162head->next = list->next;163list->next = head;164}165if(!(head = f) )166tail = NIL(Vchtree_t*);167}168else169{ if((list = head)->next == NIL(Vchtree_t*) )170break; /* tree completed */171head = tail = NIL(Vchtree_t*);172}173}174175/* turn circular list into forward list, then compute final depths */176for(s = NIL(Vchtree_t*), f = list->link; f != list; f = p)177{ p = f->link;178f->link = s;179s = f;180}181for(c = 0; s; s = s->link)182{ if((size[s-tree] += size[s->next-tree]) > c)183c = size[s-tree];184/**/DEBUG_ASSERT(size[s-tree] > 0 && size[s-tree] <= 32);185}186187free(tree);188free(sort);189190return c;191}192193194