bstr.c

00001 #include "bstr.h"
00002 
00003 #include <stdlib.h>
00004 #include <string.h>
00005 #include <stdio.h>
00006 
00007 cp_bstr *cp_bstr_create(int length, unsigned char *bits)
00008 {
00009     int bytecount;
00010     cp_bstr *seq = (cp_bstr *) malloc(sizeof(cp_bstr));
00011     if (seq == NULL) return NULL;
00012 
00013     bytecount = (length + 7) >> 3;
00014     seq->bits = (unsigned char *) malloc(bytecount);
00015     if (seq->bits == NULL)
00016     {
00017         free(seq);
00018         return NULL;
00019     }
00020 
00021     if (bits != NULL)
00022         memcpy(seq->bits, bits, bytecount);
00023 
00024     seq->length = length;
00025 
00026     return seq;
00027 }
00028 
00029 /*
00030  * initialize from a string that looks like "1010101" - convenience function 
00031  * for debugging.
00032  */
00033 cp_bstr *cstr_to_bstr(char *str)
00034 {
00035     int i, pos, len, bytecount, bit;
00036     cp_bstr *seq;
00037 
00038     seq = (cp_bstr *) malloc(sizeof(cp_bstr));
00039     if (seq == NULL) return NULL;
00040 
00041     len = strlen(str);
00042     bytecount = (len + 7) / 8;
00043     
00044     seq->bits = (unsigned char *) calloc(1, bytecount);
00045     if (seq->bits == NULL)
00046     {
00047         free(seq);
00048         return NULL;
00049     }
00050 
00051     seq->length = len;
00052     for (i = 0, pos = 0, bit = 0x80; i < len; i++)
00053     {
00054         if (str[i] == '1')
00055             seq->bits[pos] |= bit;
00056         bit >>= 1;
00057         if (bit == 0)
00058         {
00059             bit = 0x80;
00060             pos++;
00061         }
00062     }
00063         
00064     return seq;
00065 }
00066 
00067 void cp_bstr_destroy(cp_bstr *seq)
00068 {
00069     if (seq)
00070     {
00071         free(seq->bits);
00072         free(seq);
00073     }
00074 }
00075 
00076 void cp_bstr_dump(cp_bstr *seq)
00077 {
00078     int i, pos;
00079 
00080     printf("bit sequence: %d bits\n", seq->length);
00081 
00082     for (i = 0, pos = 0; i < seq->length; i++)
00083     {
00084         if (seq->bits[pos] & (0x80 >> (i % 8))) 
00085             printf("1");
00086         else
00087             printf("0");
00088 
00089         if (((i + 1) % 8) == 0) pos++;
00090     }
00091 
00092     printf("\n");
00093 }
00094 
00095 char *cp_bstr_to_string(cp_bstr *seq)
00096 {
00097     int i, pos;
00098     char *res = (char *) malloc(seq->length + 1);
00099     if (res == NULL) return NULL;
00100     
00101     for (i = 0, pos = 0; i < seq->length; i++)
00102     {
00103         if (seq->bits[pos] & (0x80 >> (i % 8))) 
00104             res[i] = '1';
00105         else
00106             res[i] = '0';
00107 
00108         if (((i + 1) % 8) == 0) pos++;
00109     }
00110 
00111     res[i] = '\0';
00112 
00113     return res;
00114 }
00115 
00116 cp_bstr *cp_bstr_dup(cp_bstr *seq)
00117 {
00118     int bytecount;
00119     cp_bstr *dup;
00120    
00121     dup = (cp_bstr *) malloc(sizeof(cp_bstr));
00122     if (dup == NULL) return NULL;
00123 
00124     bytecount = BYTECOUNT(seq);
00125     dup->bits = (unsigned char *) malloc(bytecount);
00126     if (dup->bits == NULL)
00127     {
00128         free(dup);
00129         return NULL;
00130     }
00131 
00132     memcpy(dup->bits, seq->bits, bytecount);
00133     dup->length = seq->length;
00134 
00135     return dup;
00136 }
00137 
00138 cp_bstr *cp_bstr_cpy(cp_bstr *dst, cp_bstr *src)
00139 {
00140     int bytecount_src, bytecount_dst;
00141 
00142     bytecount_src = BYTECOUNT(src);
00143     bytecount_dst = BYTECOUNT(dst);
00144 
00145     if (bytecount_src > bytecount_dst)
00146     {
00147         if (dst->length > 0)
00148             free(dst->bits);
00149 
00150         dst->bits = (unsigned char *) malloc(bytecount_src);
00151         if (dst->bits == NULL) return NULL;
00152     }
00153 
00154     memcpy(dst->bits, src->bits, bytecount_dst);
00155     src->length = dst->length;
00156 
00157     return dst;
00158 }
00159 
00160 static unsigned char bstr_mask[] = 
00161 { 
00162     0x80, // 10000000
00163     0xC0, // 11000000 
00164     0xE0, // 11100000 
00165     0xF0, // 11110000 
00166     0xF8, // 11111000 
00167     0xFC, // 11111100 
00168     0xFE, // 11111110 
00169     0xFF  // 11111111
00170 };
00171 
00172 cp_bstr *cp_bstr_cat(cp_bstr *head, cp_bstr *tail)
00173 {
00174     int old_bytecount = BYTECOUNT(head);
00175     int pos = head->length;
00176     int cpos = old_bytecount << 3;
00177     int diff = cpos - pos;
00178     int newlen = head->length + tail->length;
00179     int new_bytecount = (newlen + 7) >> 3;
00180 
00181     int in_place = head == tail;
00182     if (in_place)
00183         tail = cp_bstr_dup(tail);
00184 
00185     if (new_bytecount > old_bytecount)
00186     {
00187         unsigned char *p = (unsigned char *) malloc(new_bytecount);
00188         if (p == NULL) return NULL;
00189 
00190         memcpy(p, head->bits, old_bytecount);
00191         free(head->bits);
00192         head->bits = p;
00193     }
00194 
00195     if (diff == 0) // we're on a character boundary
00196     {
00197         memcpy(&head->bits[old_bytecount], tail->bits, BYTECOUNT(tail));
00198     }
00199     else
00200     {
00201         int i;
00202 
00203         /* example:
00204          *   head      tail               
00205          *   101      10100001 
00206          *      ^---- pos: head->length = 3  diff = 5
00207          */
00208         int stretch = new_bytecount - old_bytecount;
00209         head->bits[old_bytecount - 1] &= bstr_mask[(head->length % 8) - 1];
00210         for (i = 0; i < stretch; i++)
00211         {
00212             head->bits[old_bytecount - 1 + i] |= tail->bits[i] >> (8 - diff);
00213             head->bits[old_bytecount + i] = tail->bits[i] << diff;
00214         }
00215         if (stretch < BYTECOUNT(tail))
00216             head->bits[old_bytecount + stretch - 1] |= tail->bits[stretch] >> (8 - diff);
00217     }
00218 
00219     head->length = newlen;
00220 
00221     if (in_place)
00222         cp_bstr_destroy(tail);
00223 
00224     return head;
00225 }
00226 
00227 int cp_bstr_cmp(cp_bstr *a, cp_bstr *b, int *rpos)
00228 {
00229     int pos;
00230     int ca, cb, len;
00231     int atail, btail;
00232     int acmp, bcmp, shift;
00233     unsigned long long *llpa;
00234     unsigned long long *llpb;
00235     int llen;
00236 
00237     ca = BYTECOUNT(a);
00238     atail = ca * 8 - a->length;
00239     if (atail > 0) ca--;
00240 
00241     cb = BYTECOUNT(b);
00242     btail = cb * 8 - b->length;
00243     if (btail > 0) cb--;
00244 
00245     len = ca < cb ? ca : cb;
00246 
00247     pos = 0;
00248 
00249     if (len > sizeof(long long))
00250     {
00251         llpa = a->bits;
00252         llpb = b->bits;
00253         llen = len / 8;
00254 
00255         for ( ; pos < llen; pos++)
00256         {
00257             if (*llpa != *llpb)
00258                 break;
00259             llpa++;
00260             llpb++;
00261         }
00262         if (pos != llen)
00263         {
00264             pos *= sizeof(long long);
00265             pos += CP_CLZ_LONG_LONG(*llpa ^ *llpb);
00266             goto FOUND;
00267         }
00268         pos *= sizeof(long long);
00269     }
00270 
00271     for ( ; pos < len; pos++)
00272         if (a->bits[pos] != b->bits[pos]) 
00273             break;
00274 FOUND:
00275     if (pos < len)
00276     {
00277         if (rpos != NULL)
00278             *rpos = pos * 8 + CP_CLZ_CHAR(a->bits[pos] ^ b->bits[pos]);
00279 
00280         return a->bits[pos] - b->bits[pos];
00281     }
00282 
00283     acmp = bcmp = -1;
00284     shift = 0;
00285 
00286     if (len < ca) 
00287         acmp = a->bits[len];
00288     else if (atail > 0)
00289     {
00290         acmp = a->bits[len] & bstr_mask[7 - atail];
00291         shift = atail;
00292     }
00293 
00294     if (len < cb)
00295         bcmp = b->bits[len];
00296     else if (btail > 0)
00297     {
00298         bcmp = b->bits[len] & bstr_mask[7 - btail];
00299 #define BMAX(a, b) ((a) > (b) ? (a) : (b))
00300         shift = BMAX(shift, btail);
00301     }
00302 
00303     if (acmp != -1 && bcmp != -1)
00304     {
00305         if (shift)
00306         {
00307             acmp >>= shift;
00308             bcmp >>= shift;
00309         }
00310 
00311         if (acmp == bcmp)
00312         {
00313             len = a->length - b->length;
00314             if (rpos != NULL)
00315                 *rpos = len < 0 ? a->length : b->length;
00316             return len;
00317         }
00318         else
00319         {
00320             if (rpos != NULL)
00321                 *rpos = (pos * 8 + CP_CLZ_CHAR(acmp ^ bcmp)) - shift;
00322             return (acmp - bcmp) << shift;
00323         }
00324     }
00325 
00326     if (rpos != NULL)
00327         *rpos = pos * 8;
00328 
00329     return 0;
00330 }
00331 
00332 /*
00333  * shift bits left by the specified count, resulting in a shorter bit sequence
00334  */
00335 int cp_bstr_shift_left(cp_bstr *seq, int count)
00336 {
00337     int i;
00338     int bytes = count / 8;
00339     int bits = count - bytes * 8;
00340     int len = BYTECOUNT(seq) - bytes;
00341 
00342     if (len > 0)
00343         memmove(seq->bits, &seq->bits[bytes], len);
00344 
00345     if (bits > 0)
00346     {
00347         seq->bits[0] <<= bits;
00348         for (i = 1; i < len; i++)
00349         {
00350             seq->bits[i - 1] |= seq->bits[i] >> (8 - bits);
00351             seq->bits[i] <<= bits;
00352         }
00353     }
00354 
00355     seq->length -= count;
00356 
00357     return seq->length;
00358 }
00359 

Generated on Mon Dec 5 23:00:21 2011 for cprops by  doxygen 1.4.7