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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: memory_store.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:19:14  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: memory_store.cpp,v 1000.1 2004/06/01 19:19: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:  Vladimir Soussov
  35.  *
  36.  * File Description:  RAM storage implementation
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include "memory_store.hpp"
  41. #include <string.h>
  42. BEGIN_NCBI_SCOPE
  43. CMemStore::SMemBlock* CMemStore::x_AddBlock(void)
  44. {
  45.     SMemBlock* n_blk = new SMemBlock;
  46.     if ( !n_blk )
  47.         return 0;
  48.     n_blk->body = new char[m_BlockSize];
  49.     if ( !n_blk->body ) {
  50.         delete n_blk;
  51.         return 0;
  52.     }
  53.     n_blk->next       = 0;
  54.     n_blk->free_space = m_BlockSize;
  55.     n_blk->prev       = m_Last;
  56.     if (m_First) {
  57.         m_Last->next = n_blk;
  58.     } else {
  59.         m_First = m_Current = n_blk;
  60.     }
  61.     m_Last = n_blk;
  62.     return n_blk;
  63. }
  64. size_t CMemStore::Append(const void* buff, size_t size)
  65. {
  66.     if (!buff  ||  !size)
  67.         return 0;
  68.     if (!m_Last  ||  !m_Last->free_space) {
  69.         if ( !x_AddBlock() )
  70.             return 0;
  71.     }
  72.     TSize f_free;
  73.     TSize n = 0;
  74.     char* b = (char*) buff;
  75.     if(size > kMax_BlobSize) size= kMax_BlobSize;
  76.     TSize nof_bytes = (TSize) size;
  77.     while (nof_bytes > 0) {
  78.         f_free = m_BlockSize - m_Last->free_space;
  79.         if (nof_bytes <= m_Last->free_space) {
  80.             // we have enough space in last block
  81.             memcpy(&m_Last->body[f_free], b+n, nof_bytes);
  82.             m_Last->free_space -= nof_bytes;
  83.             n                  += nof_bytes;
  84.             break;
  85.         }
  86.         // space in this block is insufficient
  87.         memcpy(&m_Last->body[f_free], b + n, m_Last->free_space);
  88.         n         += m_Last->free_space;
  89.         nof_bytes -= m_Last->free_space;
  90.         m_Last->free_space = 0;
  91.         if ( !x_AddBlock() )
  92.             break;
  93.     }
  94.     m_Size += n;
  95.     return (size_t) n;
  96. }
  97. size_t CMemStore::Read(void* buff, size_t size)
  98. {
  99.     if (!m_Current  ||  !buff  ||  !size)
  100.         return 0;
  101.     if(size > kMax_BlobSize) size= kMax_BlobSize;
  102.     TSize n = 0;
  103.     char* b = (char*) buff;
  104.     for (TSize nof_bytes = (TSize) size;  nof_bytes > 0; ) {
  105.         TSize f_free = m_BlockSize - m_Current->free_space;
  106.         if ((m_BlockPos + nof_bytes) <= f_free) {
  107.             // we have all needed bytes in this block
  108.             memcpy(b, &m_Current->body[m_BlockPos], nof_bytes);
  109.             m_BlockPos += nof_bytes;
  110.             n += nof_bytes;
  111.             if (m_BlockPos >= f_free) {
  112.                 // we have read all bytes from this block
  113.                 m_Current = m_Current->next;
  114.                 m_BlockPos = 0;
  115.             }
  116.             break;
  117.         }
  118.         // we can read just a  part from this block
  119.         TSize k = f_free - m_BlockPos;
  120.         memcpy(b, &m_Current->body[m_BlockPos], k);
  121.         n         += k;
  122.         b         += k;
  123.         nof_bytes -= k;
  124.         m_BlockPos = 0;
  125.         m_Current = m_Current->next;
  126.         if ( !m_Current )
  127.             break;
  128.     }
  129.     m_Pos += n;
  130.     return (size_t) n;
  131. }
  132. CMemStore::TSize CMemStore::x_SeekCURR(CMemStore::TSize offset)
  133. {
  134.     if ( !m_Current )
  135.         return x_SeekTAIL(offset);
  136.     if (offset == 0)
  137.         return m_Pos;
  138.     if (offset <= -m_Pos)
  139.         return x_SeekHEAD(0);
  140.     if (offset > 0) {
  141.         // go toward the tail
  142.         while (offset > 0) {
  143.             TSize n = m_BlockSize - m_Current->free_space;
  144.             if ((m_BlockPos + offset) < n) {
  145.                 // we have to move inside this block
  146.                 m_BlockPos += offset;
  147.                 m_Pos      += offset;
  148.                 break;
  149.             }
  150.             // we have to move outside the block
  151.             n -= m_BlockPos;
  152.             m_Pos += n;
  153.             m_BlockPos = 0;
  154.             m_Current = m_Current->next;
  155.             if (!m_Current)
  156.                 break;
  157.             offset -= n;
  158.         }
  159.     }
  160.     else {
  161.         // go toward the head
  162.         while (offset < 0) {
  163.             if ((m_BlockPos + offset) >= 0) {
  164.                 // we have to move inside this block
  165.                 m_BlockPos += offset;
  166.                 m_Pos      += offset;
  167.                 break;
  168.             }
  169.             // we have to move outside the block
  170.             m_Pos  -= m_BlockPos + 1;
  171.             offset += m_BlockPos + 1;
  172.             m_Current = m_Current->prev;
  173.             m_BlockPos = m_BlockSize - (m_Current->free_space + 1);
  174.         }
  175.     }
  176.     return m_Pos;
  177. }
  178. CMemStore::TSize CMemStore::x_SeekHEAD(CMemStore::TSize offset)
  179. {
  180.     if (offset <= 0) {
  181.         m_Current  = m_First;
  182.         m_Pos      = 0;
  183.         m_BlockPos = 0;
  184.         return 0;
  185.     }
  186.     if (offset == m_Pos)
  187.         return m_Pos;
  188.     if (!m_Current  ||  (offset < m_Pos  &&  offset < m_Pos - offset)) {
  189.         x_SeekHEAD(0);
  190.         return x_SeekCURR(offset);
  191.     }
  192.     return x_SeekCURR(offset - m_Pos);
  193. }
  194. CMemStore::TSize CMemStore::x_SeekTAIL(CMemStore::TSize offset)
  195. {
  196.     if (offset >= 0) {
  197.         m_BlockPos = 0;
  198.         m_Current  = 0;
  199.         m_Pos      = m_Size;
  200.         return m_Pos;
  201.     }
  202.     return x_SeekHEAD(m_Size + offset);
  203. }
  204. long CMemStore::Seek(long offset, EWhence whence)
  205. {
  206.     if ( !m_Last )
  207.         return -1;
  208.     switch (whence) {
  209.     case eHead:
  210.         return (long) x_SeekHEAD((TSize) offset);
  211.     case eTail:
  212.         return (long) x_SeekTAIL((TSize) offset);
  213.     case eCurr:
  214.         return (long) x_SeekCURR((TSize) offset);
  215.     }
  216.     return -1;  // error
  217. }
  218. size_t CMemStore::Write(const void* buff, size_t size)
  219. {
  220.     if (!buff  ||  !size)
  221.         return 0;
  222.     if(size > kMax_BlobSize) size= kMax_BlobSize;
  223.     char* b         = (char*) buff;
  224.     TSize nof_bytes = (TSize) size;
  225.     TSize n = 0;
  226.     if ( m_Current ) {
  227.         while (nof_bytes > 0) {
  228.             TSize f_free = m_BlockSize - m_Current->free_space;
  229.             if ((m_BlockPos + nof_bytes) <= f_free) {
  230.                 // we have all needed bytes in this block
  231.                 memcpy(&m_Current->body[m_BlockPos], b + n, nof_bytes);
  232.                 m_BlockPos += nof_bytes;
  233.                 n          += nof_bytes;
  234.                 nof_bytes = 0;
  235.                 if (m_BlockPos >= f_free) {
  236.                     // we have written all bytes to this block
  237.                     m_Current = m_Current->next;
  238.                     m_BlockPos = 0;
  239.                 }
  240.                 break;
  241.             }
  242.             // we can write just a part to this block
  243.             TSize k = f_free - m_BlockPos;
  244.             memcpy(&m_Current->body[m_BlockPos], b + n, k);
  245.             n         += k;
  246.             nof_bytes -= k;
  247.             m_BlockPos = 0;
  248.             m_Current = m_Current->next;
  249.             if ( !m_Current )
  250.                 break;
  251.         }
  252.     }
  253.     if (nof_bytes > 0) {
  254.         n += Append(b + n, nof_bytes);
  255.         x_SeekTAIL(0);
  256.     }
  257.     else {
  258.         m_Pos += n;
  259.     }
  260.     return n;
  261. }
  262. size_t CMemStore::Truncate(size_t size)
  263. {
  264.     if(size > kMax_BlobSize) size= kMax_BlobSize;
  265.     TSize nof_bytes = (TSize) size;
  266.     if (nof_bytes >= m_Size) {
  267.         for ( ;  m_Last != NULL;  m_Last = m_Current) {
  268.             m_Current = m_Last->prev;
  269.             delete m_Last->body;
  270.             delete m_Last;
  271.         }
  272. m_First = m_Last = m_Current = 0;        
  273. m_BlockPos = m_Pos = m_Size = 0;
  274.         return 0;
  275.     }
  276.     while (nof_bytes > 0) {
  277.         TSize n = m_BlockSize - m_Last->free_space;
  278.         if (n <= nof_bytes) {
  279.             // we have to delete the whole block
  280.             delete m_Last->body;
  281.             SMemBlock* t = m_Last->prev;
  282.             if ( t ) {
  283.                 t->next = 0;
  284.             }
  285.             delete m_Last;
  286.             m_Last = t;
  287.             nof_bytes -= n;
  288.             m_Size    -= n;
  289.             continue;
  290.         }
  291.         // we have to free some bytes
  292.         m_Last->free_space -= nof_bytes;
  293.         m_Size             -= nof_bytes;
  294.         break;
  295.     }
  296.     if (m_Pos >= m_Size) {
  297.         m_Pos      = m_Size;
  298.         m_Current  = 0;
  299.         m_BlockPos = 0;
  300.     }
  301.     return m_Size;
  302. }
  303. size_t CMemStore::Insert(const void* buff, size_t size)
  304. {
  305.     if (!buff  ||  !size)
  306.         return 0;
  307.     if(size > kMax_BlobSize) size= kMax_BlobSize;
  308.     if ( !m_Current )
  309.         return Append(buff, size);
  310.     char* b         = (char*) buff;
  311.     TSize nof_bytes = (TSize) size;
  312.     TSize n = 0;
  313.     while (nof_bytes > 0) {
  314.         // first empty byte in this block
  315.         TSize f_free = m_BlockSize - m_Current->free_space;
  316.         // number of bytes to move
  317.         TSize k      = f_free - m_BlockPos;
  318.         if (nof_bytes <= m_Current->free_space) {
  319.             // we can add this to existing block
  320.             memmove(&m_Current->body[m_BlockPos + nof_bytes],
  321.                     &m_Current->body[m_BlockPos], k);
  322.             memcpy(&m_Current->body[m_BlockPos], b + n, nof_bytes);
  323.             m_Current->free_space -= nof_bytes;
  324.             n                     += nof_bytes;
  325.             m_BlockPos            += nof_bytes;
  326.             nof_bytes = 0;
  327.             break;
  328.         }
  329.         // there is no enaugh space in existing block -- split it
  330.         SMemBlock* t_block = new SMemBlock;
  331.         t_block->body = new char[m_BlockSize];
  332.         t_block->next = m_Current->next;
  333.         if (t_block->next)
  334.             t_block->next->prev = t_block;
  335.         m_Current->next = t_block;
  336.         t_block->prev = m_Current;
  337.         memcpy(t_block->body, &m_Current->body[m_BlockPos], k);
  338.         t_block->free_space = m_BlockSize - k;
  339.         m_Current->free_space += k;
  340.         k = (nof_bytes <= m_Current->free_space)
  341.             ? nof_bytes : m_Current->free_space;
  342.         memcpy(&m_Current->body[m_BlockPos], b + n, k);
  343.         m_Current->free_space -= k;
  344.         nof_bytes             -= k;
  345.         n                     += k;
  346.         if (m_Last == m_Current)
  347.             m_Last = t_block;
  348.         m_Current  = t_block;
  349.         m_BlockPos = 0;
  350.     }
  351.     m_Pos  += n;
  352.     m_Size += n;
  353.     // try to merge the two last blocks
  354.     SMemBlock* t_block = m_Current->next;
  355.     if ((m_Current->free_space + t_block->free_space) >= m_BlockSize) {
  356.         TSize f_free = m_BlockSize - m_Current->free_space;
  357.         TSize k      = m_BlockSize - t_block->free_space;
  358.         memcpy(&m_Current->body[f_free], t_block->body, k);
  359.         m_Current->free_space -= k;
  360.         m_Current->next = t_block->next;
  361.         if (m_Current->next) {
  362.             m_Current->next->prev = m_Current;
  363.         } else {
  364.             m_Last = m_Current;
  365.         }
  366.         delete t_block->body;
  367.         delete t_block;
  368.     }
  369.     return n;
  370. }
  371. size_t CMemStore::Delete(size_t size)
  372. {
  373.     if (!m_Last  ||  !size == 0)
  374.         return m_Size;
  375.     if(size > kMax_BlobSize) size= kMax_BlobSize;
  376.     if ( !m_Current )
  377.         return Truncate(size);
  378.     TSize nof_bytes = (TSize) size;
  379.     if (m_BlockPos >= nof_bytes) {
  380.         // just one block is affected
  381.         memmove(&m_Current->body[m_BlockPos - nof_bytes],
  382.                 &m_Current->body[m_BlockPos],
  383.                 m_BlockSize - m_Current->free_space - m_BlockPos);
  384.         m_Current->free_space += nof_bytes;
  385.         m_BlockPos            -= nof_bytes;
  386.         m_Pos                 -= nof_bytes;
  387.         m_Size                -= nof_bytes;
  388.         return m_Size;
  389.     }
  390.     // we can affect several blocks...
  391.     if (m_BlockPos > 0) {
  392.         memmove(m_Current->body, &m_Current->body[m_BlockPos],
  393.                 m_BlockSize - m_Current->free_space - m_BlockPos);
  394.         m_Current->free_space += m_BlockPos;
  395.         nof_bytes             -= m_BlockPos;
  396.         m_Pos                 -= m_BlockPos;
  397.         m_Size                -= m_BlockPos;
  398.         m_BlockPos = 0;
  399.     }
  400.     while (nof_bytes > 0) {
  401.         SMemBlock* t_block = m_Current->prev;
  402.         if ( !t_block ) {
  403.             m_First = m_Current;
  404.             break;
  405.         }
  406.         TSize n = m_BlockSize - t_block->free_space; // # of bytes in this block
  407.         if (nof_bytes < n) {
  408.             // all we have to delete is inside the block
  409.             t_block->free_space += nof_bytes;
  410.             m_Pos               -= nof_bytes;
  411.             m_Size              -= nof_bytes;
  412.             break;
  413.         }
  414.         // delete the whole block
  415.         if (t_block->prev)
  416.             t_block->prev->next = m_Current;
  417.         else
  418.             m_First = m_Current;
  419.         m_Current->prev = t_block->prev;
  420.         delete t_block->body;
  421.         delete t_block;
  422.         m_Pos     -= n;
  423.         m_Size    -= n;
  424.         nof_bytes -= n;
  425.     }
  426.     return m_Size;
  427. }
  428. CMemStore::CMemStore(C_SA_Storage& storage, size_t block_size)
  429. {
  430.     if(block_size > kMax_BlobSize) block_size= kMax_BlobSize;
  431.     x_Init((TSize) block_size);
  432.     char* buff = new char[m_BlockSize];
  433.     TSize n;
  434.     while ((n = storage.Read(buff, (size_t) m_BlockSize)) > 0) {
  435.         Append(buff, n);
  436.         if (n < m_BlockSize)
  437.             break;
  438.     }
  439. }
  440. CMemStore::~CMemStore()
  441. {
  442.     while ( m_Last ) {
  443.         m_Current = m_Last->prev;
  444.         delete [] m_Last->body;
  445.         delete m_Last;
  446.         m_Last = m_Current;
  447.     }
  448. }
  449. END_NCBI_SCOPE
  450. /*
  451.  * ===========================================================================
  452.  * $Log: memory_store.cpp,v $
  453.  * Revision 1000.1  2004/06/01 19:19:14  gouriano
  454.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8
  455.  *
  456.  * Revision 1.8  2004/05/17 21:11:38  gorelenk
  457.  * Added include of PCH ncbi_pch.hpp
  458.  *
  459.  * Revision 1.7  2003/10/28 19:37:08  soussov
  460.  * fixes memory leak in CMemStore::Truncate
  461.  *
  462.  * Revision 1.6  2002/09/13 18:43:18  soussov
  463.  * fixes compiler warnings
  464.  *
  465.  * Revision 1.5  2002/09/13 18:27:02  soussov
  466.  * fixed bug with long overflow
  467.  *
  468.  * Revision 1.4  2002/03/20 22:23:12  soussov
  469.  * fixes bug in Truncate method
  470.  *
  471.  * Revision 1.3  2002/01/24 16:14:28  soussov
  472.  * makes purify happy
  473.  *
  474.  * Revision 1.2  2001/11/06 17:59:53  lavr
  475.  * Formatted uniformly as the rest of the library
  476.  *
  477.  * Revision 1.1  2001/09/21 23:39:59  vakatov
  478.  * -----  Initial (draft) revision.  -----
  479.  * This is a major revamp (by Denis Vakatov, with help from Vladimir Soussov)
  480.  * of the DBAPI "driver" libs originally written by Vladimir Soussov.
  481.  * The revamp involved massive code shuffling and grooming, numerous local
  482.  * API redesigns, adding comments and incorporating DBAPI to the C++ Toolkit.
  483.  *
  484.  * ===========================================================================
  485.  */