ncbi_buffer.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:10k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_buffer.c,v $
  4.  * PRODUCTION Revision 1000.1  2004/02/12 21:52:14  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [CORE_001] Dev-tree R6.13
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_buffer.c,v 1000.1 2004/02/12 21:52:14 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Denis Vakatov
  35.  *
  36.  * File Description:
  37.  *   Memory-resident FIFO storage area (to be used e.g. in I/O buffering)
  38.  *
  39.  */
  40. #include <connect/ncbi_buffer.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <assert.h>
  44. #ifndef NDEBUG
  45. /* NOTE: this conditional inclusion is only needed by assert.h on Darwin!
  46.  * We do not want to include "ncbi_config.h" to additionally branch on
  47.  * NCBI_OS_DAWRIN here because in C toolkit it in turn pulls ncbilcl.h,
  48.  * which includes <stdio.h>, thus making this conditional unnecessary.
  49.  */
  50. #  include <stdio.h>
  51. #endif
  52. /* Buffer chunk
  53.  */
  54. typedef struct SBufChunkTag {
  55.     struct SBufChunkTag* next;
  56.     size_t size;       /* of data (including the discarded "n_skip" bytes)  */
  57.     size_t alloc_size; /* maximum available (allocated) size of "data"      */
  58.     size_t n_skip;     /* # of bytes already discarded(read) from the chunk */
  59.     char   data[1];    /* data stored in this chunk                         */
  60. } SBufChunk;
  61. /* Buffer
  62.  */
  63. typedef struct BUF_tag {
  64.     size_t     chunk_size; /* this is actually a chunk size unit */
  65.     SBufChunk* list;
  66.     SBufChunk* last;
  67. } BUF_struct;
  68. extern size_t BUF_SetChunkSize(BUF* pBuf, size_t chunk_size)
  69. {
  70.     /* create buffer internals, if not created yet */
  71.     if ( !*pBuf ) {
  72.         *pBuf = (BUF_struct*) malloc(sizeof(BUF_struct));
  73.         if ( !*pBuf )
  74.             return 0;
  75.         (*pBuf)->list = (*pBuf)->last = 0;
  76.     }
  77.     /* and set the min. mem. chunk size */
  78.     (*pBuf)->chunk_size = chunk_size ? chunk_size : BUF_DEF_CHUNK_SIZE;
  79.     return (*pBuf)->chunk_size;
  80. }
  81. extern size_t BUF_Size(BUF buf)
  82. {
  83.     size_t     size;
  84.     SBufChunk* pChunk;
  85.     if ( !buf )
  86.         return 0;
  87.     for (size = 0, pChunk = buf->list;  pChunk;  pChunk = pChunk->next) {
  88.         assert(pChunk->size > pChunk->n_skip);
  89.         size += pChunk->size - pChunk->n_skip;
  90.     }
  91.     return size;
  92. }
  93. /* Create a new chunk.
  94.  * Allocate at least "chunk_size" bytes, but no less than "size" bytes.
  95.  */
  96. static SBufChunk* s_AllocChunk(size_t size, size_t chunk_size)
  97. {
  98.     size_t alloc_size = ((size + chunk_size - 1) / chunk_size) * chunk_size;
  99.     SBufChunk* pChunk = (SBufChunk*)
  100.         malloc((size_t) (&(((SBufChunk*)0)->data)) + alloc_size);
  101.     if ( !pChunk )
  102.         return 0;
  103.     pChunk->next       = 0;
  104.     pChunk->size       = 0;
  105.     pChunk->alloc_size = alloc_size;
  106.     pChunk->n_skip     = 0;
  107.     return pChunk;
  108. }
  109. extern int/*bool*/ BUF_Write(BUF* pBuf, const void* data, size_t size)
  110. {
  111.     SBufChunk *pChunk, *pTail;
  112.     if ( !size )
  113.         return 1 /* true */;
  114.     /* init the buffer internals, if not init'd yet */
  115.     if (!*pBuf  &&  !BUF_SetChunkSize(pBuf, 0) )
  116.         return 0 /* false */;
  117.     /* find the last allocated chunk */
  118.     pTail = (*pBuf)->last;
  119.     /* write to an unfilled space of the last allocated chunk, if any */
  120.     if (pTail  &&  pTail->size != pTail->alloc_size) {
  121.         size_t n_avail = pTail->alloc_size - pTail->size;
  122.         size_t n_write = (size <= n_avail) ? size : n_avail;
  123.         assert(pTail->size < pTail->alloc_size);
  124.         memcpy(pTail->data + pTail->size, data, n_write);
  125.         pTail->size += n_write;
  126.         size -= n_write;
  127.         data = (char*) data + n_write;
  128.     }
  129.     /* allocate and write to the new chunk, if necessary */
  130.     if ( size ) {
  131.         pChunk = s_AllocChunk(size, (*pBuf)->chunk_size);
  132.         if ( !pChunk )
  133.             return 0 /* false */;
  134.         pChunk->n_skip = 0;
  135.         pChunk->size   = size;
  136.         memcpy(pChunk->data, data, size);
  137.         /* add the new chunk to the list */
  138.         if ( pTail )
  139.             pTail->next = pChunk;
  140.         else
  141.             (*pBuf)->list = pChunk;
  142.         (*pBuf)->last = pChunk;
  143.     }
  144.     return 1 /* true */;
  145. }
  146. extern int/*bool*/ BUF_PushBack(BUF* pBuf, const void* data, size_t size)
  147. {
  148.     SBufChunk* pChunk;
  149.     if ( !size )
  150.         return 1 /* true */;
  151.     /* init the buffer internals, if not init'd yet */
  152.     if (!*pBuf  &&  !BUF_SetChunkSize(pBuf, 0) )
  153.         return 0 /* false */;
  154.     pChunk = (*pBuf)->list;
  155.     /* allocate and link a new chunk to the beginning of the chunk list */
  156.     if (!pChunk  ||  size > pChunk->n_skip) {
  157.         pChunk = s_AllocChunk(size, (*pBuf)->chunk_size);
  158.         if ( !pChunk )
  159.             return 0 /* false */;
  160.         pChunk->n_skip = pChunk->size = pChunk->alloc_size;
  161.         pChunk->next  = (*pBuf)->list;
  162.         (*pBuf)->list = pChunk;
  163.         if ( !(*pBuf)->last ) {
  164.             (*pBuf)->last = pChunk;
  165.         }
  166.     }
  167.     /* write data */
  168.     assert(pChunk->n_skip >= size);
  169.     pChunk->n_skip -= size;
  170.     memcpy(pChunk->data + pChunk->n_skip, data, size);
  171.     return 1 /* true */;
  172. }
  173. extern size_t BUF_Peek(BUF buf, void* data, size_t size)
  174. {
  175.     return BUF_PeekAt(buf, 0, data, size);
  176. }
  177. extern size_t BUF_PeekAt(BUF buf, size_t pos, void* data, size_t size)
  178. {
  179.     size_t     n_todo = size;
  180.     size_t     n_extra_skip = 0;
  181.     SBufChunk* pChunk;
  182.     if (!size  ||  !buf  ||  !buf->list)
  183.         return 0;
  184.     /* special treatment for NULL data buffer */
  185.     if ( !data ) {
  186.         size_t buf_size = BUF_Size(buf);
  187.         if (buf_size <= pos)
  188.             return 0;
  189.         buf_size -= pos;
  190.         return buf_size < size ? buf_size : size;
  191.     }
  192.     /* skip "pos" bytes */
  193.     for (pChunk = buf->list;  pChunk;  pChunk = pChunk->next) {
  194.         size_t chunk_size = pChunk->size - pChunk->n_skip;
  195.         assert(pChunk->size > pChunk->n_skip);
  196.         if (chunk_size > pos) {
  197.             n_extra_skip = pos;
  198.             break;
  199.         }
  200.         pos -= chunk_size;
  201.     }
  202.     /* copy the peeked data to "buf" */
  203.     for ( ;  n_todo  &&  pChunk;  pChunk = pChunk->next, n_extra_skip = 0) {
  204.         size_t n_skip = pChunk->n_skip + n_extra_skip;
  205.         size_t n_copy = pChunk->size - n_skip;
  206.         assert(pChunk->size > n_skip);
  207.         if (n_copy > n_todo)
  208.             n_copy = n_todo;
  209.         memcpy(data, (char*) pChunk->data + n_skip, n_copy);
  210.         data = (char*) data + n_copy;
  211.         n_todo -= n_copy;
  212.     }
  213.     assert(size >= n_todo);
  214.     return (size - n_todo);
  215. }
  216. extern size_t BUF_Read(BUF buf, void* data, size_t size)
  217. {
  218.     size_t n_todo;
  219.     if (!buf  ||  !size)
  220.         return 0;
  221.     /* peek to the callers data buffer, if non-NULL */
  222.     if ( data )
  223.         size = BUF_PeekAt(buf, 0, data, size);
  224.     /* remove the read data from the buffer */ 
  225.     n_todo = size;
  226.     while (n_todo  &&  buf->list) {
  227.         SBufChunk* pHead = buf->list;
  228.         size_t     n_avail = pHead->size - pHead->n_skip;
  229.         if (n_todo >= n_avail) { /* discard the whole chunk */
  230.             buf->list = pHead->next;
  231.             if ( !buf->list ) {
  232.                 buf->last = 0;
  233.             }
  234.             free(pHead);
  235.             n_todo -= n_avail;
  236.         } else { /* discard some of the chunk data */
  237.             pHead->n_skip += n_todo;
  238.             n_todo = 0;
  239.         }
  240.     }
  241.     assert(size >= n_todo);
  242.     return (size - n_todo);
  243. }
  244. extern void BUF_Destroy(BUF buf)
  245. {
  246.     if ( !buf )
  247.         return;
  248.     while ( buf->list ) {
  249.         SBufChunk* pChunk = buf->list;
  250.         buf->list = pChunk->next;
  251.         free(pChunk);
  252.     }
  253.     free(buf);
  254. }
  255. /*
  256.  * ---------------------------------------------------------------------------
  257.  * $Log: ncbi_buffer.c,v $
  258.  * Revision 1000.1  2004/02/12 21:52:14  gouriano
  259.  * PRODUCTION: UPGRADED [CORE_001] Dev-tree R6.13
  260.  *
  261.  * Revision 6.13  2003/12/05 17:31:04  ucko
  262.  * Add a tail pointer to BUF_struct to avoid having to walk the entire
  263.  * list in BUF_Write.
  264.  *
  265.  * Revision 6.12  2003/05/14 03:49:53  lavr
  266.  * Some indentation; added comment on chunk_size being a chunk size unit
  267.  *
  268.  * Revision 6.11  2003/01/08 02:01:01  lavr
  269.  * Reindented in accordance with current coding rules
  270.  *
  271.  * Revision 6.10  2002/12/18 21:46:19  lavr
  272.  * Revised comment about conditional inclusion of <stdio.h>
  273.  *
  274.  * Revision 6.9  2002/12/18 19:30:11  lavr
  275.  * Conditional <stdio.h> on OS_UNIX_DARWIN for Mach-O executables (RGS)
  276.  *
  277.  * Revision 6.8  2002/12/13 21:18:24  lavr
  278.  * Log moved to end
  279.  *
  280.  * Revision 6.7  2001/04/23 22:20:27  vakatov
  281.  * BUF_PeekAt() -- special case for "data" == NULL
  282.  *
  283.  * Revision 6.6  2001/04/23 18:07:21  vakatov
  284.  * + BUF_PeekAt()
  285.  *
  286.  * Revision 6.5  2000/02/23 22:34:34  vakatov
  287.  * Can work both "standalone" and as a part of NCBI C++ or C toolkits
  288.  *
  289.  * Revision 6.4  1999/11/19 19:59:08  vakatov
  290.  * Get rid of an insignificant compiler warning
  291.  *
  292.  * Revision 6.3  1999/10/18 18:01:43  vakatov
  293.  * Use double-quotes (rather than angles) to #include ncbi_buffer.h
  294.  * (this kludge is to ease compilation in the NCBI C++ tree).
  295.  *
  296.  * Revision 6.2  1999/10/12 16:32:14  vakatov
  297.  * Moved all TEST suite code from "ncbi_buffer.c" to "test/test_ncbi_buffer.c"
  298.  *
  299.  * Revision 6.1  1999/08/17 19:45:22  vakatov
  300.  * Moved all real code from NCBIBUF to NCBI_BUFFER;  the code has been cleaned
  301.  * from the NCBI C toolkit specific types and API calls.
  302.  * NCBIBUF module still exists for the backward compatibility -- it
  303.  * provides old NCBI-wise interface.
  304.  *
  305.  * ===========================================================================
  306.  */