mojoshader_common.c
changeset 944 9f9fa9650772
parent 939 64cc93ee5a56
child 945 f00ea3986db8
equal deleted inserted replaced
943:775cd2ac324b 944:9f9fa9650772
   531     } // while
   531     } // while
   532     f(list, d);
   532     f(list, d);
   533 } // errorlist_destroy
   533 } // errorlist_destroy
   534 
   534 
   535 
   535 
       
   536 typedef struct BufferBlock
       
   537 {
       
   538     char *data;
       
   539     size_t bytes;
       
   540     struct BufferBlock *next;
       
   541 } BufferBlock;
       
   542 
       
   543 struct Buffer
       
   544 {
       
   545     size_t total_bytes;
       
   546     BufferBlock *head;
       
   547     BufferBlock *tail;
       
   548     size_t block_size;
       
   549     MOJOSHADER_malloc m;
       
   550     MOJOSHADER_free f;
       
   551     void *d;
       
   552 };
       
   553 
       
   554 Buffer *buffer_create(size_t blksz, MOJOSHADER_malloc m,
       
   555                       MOJOSHADER_free f, void *d)
       
   556 {
       
   557     Buffer *buffer = (Buffer *) m(sizeof (Buffer), d);
       
   558     if (buffer != NULL)
       
   559     {
       
   560         memset(buffer, '\0', sizeof (Buffer));
       
   561         buffer->block_size = blksz;
       
   562         buffer->m = m;
       
   563         buffer->f = f;
       
   564         buffer->d = d;
       
   565     } // if
       
   566     return buffer;
       
   567 } // buffer_create
       
   568 
       
   569 int buffer_append(Buffer *buffer, const char *data, size_t len)
       
   570 {
       
   571     // note that we make the blocks bigger than blocksize when we have enough
       
   572     //  data to overfill a fresh block, to reduce allocations.
       
   573     const size_t blocksize = buffer->block_size;
       
   574 
       
   575     if (len == 0)
       
   576         return 1;
       
   577 
       
   578     if (buffer->tail != NULL)
       
   579     {
       
   580         const size_t tailbytes = buffer->tail->bytes;
       
   581         const size_t avail = (tailbytes >= blocksize) ? 0 : blocksize - tailbytes;
       
   582         const size_t cpy = (avail > len) ? len : avail;
       
   583         if (cpy > 0)
       
   584         {
       
   585             memcpy(buffer->tail->data + tailbytes, data, cpy);
       
   586             len -= cpy;
       
   587             data += cpy;
       
   588             buffer->tail->bytes += cpy;
       
   589             buffer->total_bytes += cpy;
       
   590             assert(buffer->tail->bytes <= blocksize);
       
   591         } // if
       
   592     } // if
       
   593 
       
   594     if (len > 0)
       
   595     {
       
   596         assert((!buffer->tail) || (buffer->tail->bytes == blocksize));
       
   597         const size_t bytecount = len > blocksize ? len : blocksize;
       
   598         const size_t malloc_len = sizeof (BufferBlock) + bytecount;
       
   599         BufferBlock *item = (BufferBlock *) buffer->m(malloc_len, buffer->d);
       
   600         if (item == NULL)
       
   601             return 0;
       
   602 
       
   603         item->data = ((char *) item) + sizeof (BufferBlock);
       
   604         item->bytes = len;
       
   605         item->next = NULL;
       
   606         if (buffer->tail != NULL)
       
   607             buffer->tail->next = item;
       
   608         else
       
   609             buffer->head = item;
       
   610         buffer->tail = item;
       
   611 
       
   612         memcpy(item->data, data, len);
       
   613         buffer->total_bytes += len;
       
   614     } // if
       
   615 
       
   616     return 1;
       
   617 } // buffer_append
       
   618 
       
   619 int buffer_append_fmt(Buffer *buffer, const char *fmt, ...)
       
   620 {
       
   621     va_list ap;
       
   622     va_start(ap, fmt);
       
   623     const int retval = buffer_append_va(buffer, fmt, ap);
       
   624     va_end(ap);
       
   625     return retval;
       
   626 } // buffer_append_fmt
       
   627 
       
   628 int buffer_append_va(Buffer *buffer, const char *fmt, va_list va)
       
   629 {
       
   630     char scratch[128];
       
   631 
       
   632     va_list ap;
       
   633     va_copy(ap, va);
       
   634     const int len = vsnprintf(scratch, sizeof (scratch), fmt, ap);
       
   635     va_end(ap);
       
   636 
       
   637     // If we overflowed our scratch buffer, heap allocate and try again.
       
   638 
       
   639     if (len == 0)
       
   640         return 1;  // nothing to do.
       
   641     else if (len < sizeof (scratch))
       
   642         return buffer_append(buffer, scratch, len);
       
   643 
       
   644     char *buf = (char *) buffer->m(len + 1, buffer->d);
       
   645     if (buf == NULL)
       
   646         return 0;
       
   647     va_copy(ap, va);
       
   648     vsnprintf(buf, len + 1, fmt, ap);  // rebuild it.
       
   649     va_end(ap);
       
   650     const int retval = buffer_append(buffer, scratch, len);
       
   651     buffer->f(buf, buffer->d);
       
   652     return retval;
       
   653 } // buffer_append_va
       
   654 
       
   655 size_t buffer_size(Buffer *buffer)
       
   656 {
       
   657     return buffer->total_bytes;
       
   658 } // buffer_size
       
   659 
       
   660 void buffer_empty(Buffer *buffer)
       
   661 {
       
   662     BufferBlock *item = buffer->head;
       
   663     while (item != NULL)
       
   664     {
       
   665         BufferBlock *next = item->next;
       
   666         buffer->f(item, buffer->d);
       
   667         item = next;
       
   668     } // while
       
   669     buffer->head = buffer->tail = NULL;
       
   670     buffer->total_bytes = 0;
       
   671 } // buffer_empty
       
   672 
       
   673 char *buffer_flatten(Buffer *buffer)
       
   674 {
       
   675     char *retval = (char *) buffer->m(buffer->total_bytes + 1, buffer->d);
       
   676     if (retval == NULL)
       
   677         return NULL;
       
   678     BufferBlock *item = buffer->head;
       
   679     char *ptr = retval;
       
   680     while (item != NULL)
       
   681     {
       
   682         BufferBlock *next = item->next;
       
   683         memcpy(ptr, item->data, item->bytes);
       
   684         ptr += item->bytes;
       
   685         buffer->f(item, buffer->d);
       
   686         item = next;
       
   687     } // while
       
   688     *ptr = '\0';
       
   689 
       
   690     assert(ptr == (retval + buffer->total_bytes));
       
   691 
       
   692     buffer->head = buffer->tail = NULL;
       
   693     buffer->total_bytes = 0;
       
   694 
       
   695     return retval;
       
   696 } // buffer_flatten
       
   697 
       
   698 char *buffer_merge(Buffer **buffers, const size_t n, size_t *_len)
       
   699 {
       
   700     Buffer *first = NULL;
       
   701     size_t len = 0;
       
   702     size_t i;
       
   703     for (i = 0; i < n; i++)
       
   704     {
       
   705         Buffer *buffer = buffers[i];
       
   706         if (buffer == NULL)
       
   707             continue;
       
   708         if (first == NULL)
       
   709             first = buffer;
       
   710         len += buffer->total_bytes;
       
   711     } // for
       
   712 
       
   713     char *retval = (char *) first ? first->m(len + 1, first->d) : NULL;
       
   714     if (retval == NULL)
       
   715     {
       
   716         *_len = 0;
       
   717         return NULL;
       
   718     } // if
       
   719 
       
   720     *_len = len;
       
   721     char *ptr = retval;
       
   722     for (i = 0; i < n; i++)
       
   723     {
       
   724         Buffer *buffer = buffers[i];
       
   725         if (buffer == NULL)
       
   726             continue;
       
   727         BufferBlock *item = buffer->head;
       
   728         while (item != NULL)
       
   729         {
       
   730             BufferBlock *next = item->next;
       
   731             memcpy(ptr, item->data, item->bytes);
       
   732             ptr += item->bytes;
       
   733             buffer->f(item, buffer->d);
       
   734             item = next;
       
   735         } // while
       
   736 
       
   737         buffer->head = buffer->tail = NULL;
       
   738         buffer->total_bytes = 0;
       
   739     } // for
       
   740     *ptr = '\0';
       
   741 
       
   742     assert(ptr == (retval + len));
       
   743 
       
   744     return retval;
       
   745 } // buffer_merge
       
   746 
       
   747 void buffer_destroy(Buffer *buffer)
       
   748 {
       
   749     if (buffer != NULL)
       
   750     {
       
   751         MOJOSHADER_free f = buffer->f;
       
   752         void *d = buffer->d;
       
   753         buffer_empty(buffer);
       
   754         f(buffer, d);
       
   755     } // if
       
   756 } // buffer_destroy
       
   757 
   536 // end of mojoshader_common.c ...
   758 // end of mojoshader_common.c ...
   537 
   759