home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / array_s.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  9KB  |  412 lines

  1.  
  2. // This is a part of the Microsoft Foundation Classes C++ library.
  3. // Copyright (C) 1992-1998 Microsoft Corporation
  4. // All rights reserved.
  5. //
  6. // This source code is only intended as a supplement to the
  7. // Microsoft Foundation Classes Reference and related
  8. // electronic documentation provided with the library.
  9. // See these sources for detailed information regarding the
  10. // Microsoft Foundation Classes product.
  11.  
  12. /////////////////////////////////////////////////////////////////////////////
  13. //
  14. // Implementation of parameterized Array
  15. //
  16. /////////////////////////////////////////////////////////////////////////////
  17. // NOTE: we allocate an array of 'm_nMaxSize' elements, but only
  18. //  the current size 'm_nSize' contains properly constructed
  19. //  objects.
  20.  
  21. #include "stdafx.h"
  22.  
  23. #ifdef AFX_COLL_SEG
  24. #pragma code_seg(AFX_COLL_SEG)
  25. #endif
  26.  
  27. #ifdef _DEBUG
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31.  
  32. #define new DEBUG_NEW
  33.  
  34.  
  35. /////////////////////////////////////////////////////////////////////////////
  36.  
  37. #include "elements.h"  // used for special creation
  38.  
  39. static void ConstructElements(CString* pNewData, int nCount)
  40. {
  41.     ASSERT(nCount >= 0);
  42.  
  43.     while (nCount--)
  44.     {
  45.         ConstructElement(pNewData);
  46.         pNewData++;
  47.     }
  48. }
  49.  
  50. static void DestructElements(CString* pOldData, int nCount)
  51. {
  52.     ASSERT(nCount >= 0);
  53.  
  54.     while (nCount--)
  55.     {
  56.         DestructElement(pOldData);
  57.         pOldData++;
  58.     }
  59. }
  60.  
  61. static void CopyElements(CString* pDest, CString* pSrc, int nCount)
  62. {
  63.     ASSERT(nCount >= 0);
  64.  
  65.     while (nCount--)
  66.     {
  67.         *pDest = *pSrc;
  68.         ++pDest;
  69.         ++pSrc;
  70.     }
  71. }
  72.  
  73. /////////////////////////////////////////////////////////////////////////////
  74.  
  75. CStringArray::CStringArray()
  76. {
  77.     m_pData = NULL;
  78.     m_nSize = m_nMaxSize = m_nGrowBy = 0;
  79. }
  80.  
  81. CStringArray::~CStringArray()
  82. {
  83.     ASSERT_VALID(this);
  84.  
  85.  
  86.     DestructElements(m_pData, m_nSize);
  87.     delete[] (BYTE*)m_pData;
  88. }
  89.  
  90. void CStringArray::SetSize(int nNewSize, int nGrowBy)
  91. {
  92.     ASSERT_VALID(this);
  93.     ASSERT(nNewSize >= 0);
  94.  
  95.     if (nGrowBy != -1)
  96.         m_nGrowBy = nGrowBy;  // set new size
  97.  
  98.     if (nNewSize == 0)
  99.     {
  100.         // shrink to nothing
  101.  
  102.         DestructElements(m_pData, m_nSize);
  103.         delete[] (BYTE*)m_pData;
  104.         m_pData = NULL;
  105.         m_nSize = m_nMaxSize = 0;
  106.     }
  107.     else if (m_pData == NULL)
  108.     {
  109.         // create one with exact size
  110. #ifdef SIZE_T_MAX
  111.         ASSERT(nNewSize <= SIZE_T_MAX/sizeof(CString));    // no overflow
  112. #endif
  113.         m_pData = (CString*) new BYTE[nNewSize * sizeof(CString)];
  114.  
  115.         ConstructElements(m_pData, nNewSize);
  116.  
  117.         m_nSize = m_nMaxSize = nNewSize;
  118.     }
  119.     else if (nNewSize <= m_nMaxSize)
  120.     {
  121.         // it fits
  122.         if (nNewSize > m_nSize)
  123.         {
  124.             // initialize the new elements
  125.  
  126.             ConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
  127.  
  128.         }
  129.  
  130.         else if (m_nSize > nNewSize)  // destroy the old elements
  131.             DestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
  132.  
  133.         m_nSize = nNewSize;
  134.     }
  135.     else
  136.     {
  137.         // otherwise, grow array
  138.         int nGrowBy = m_nGrowBy;
  139.         if (nGrowBy == 0)
  140.         {
  141.             // heuristically determine growth when nGrowBy == 0
  142.             //  (this avoids heap fragmentation in many situations)
  143.             nGrowBy = min(1024, max(4, m_nSize / 8));
  144.         }
  145.         int nNewMax;
  146.         if (nNewSize < m_nMaxSize + nGrowBy)
  147.             nNewMax = m_nMaxSize + nGrowBy;  // granularity
  148.         else
  149.             nNewMax = nNewSize;  // no slush
  150.  
  151.         ASSERT(nNewMax >= m_nMaxSize);  // no wrap around
  152. #ifdef SIZE_T_MAX
  153.         ASSERT(nNewMax <= SIZE_T_MAX/sizeof(CString)); // no overflow
  154. #endif
  155.         CString* pNewData = (CString*) new BYTE[nNewMax * sizeof(CString)];
  156.  
  157.         // copy new data from old
  158.         memcpy(pNewData, m_pData, m_nSize * sizeof(CString));
  159.  
  160.         // construct remaining elements
  161.         ASSERT(nNewSize > m_nSize);
  162.  
  163.         ConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
  164.  
  165.  
  166.         // get rid of old stuff (note: no destructors called)
  167.         delete[] (BYTE*)m_pData;
  168.         m_pData = pNewData;
  169.         m_nSize = nNewSize;
  170.         m_nMaxSize = nNewMax;
  171.     }
  172. }
  173.  
  174. int CStringArray::Append(const CStringArray& src)
  175. {
  176.     ASSERT_VALID(this);
  177.     ASSERT(this != &src);   // cannot append to itself
  178.  
  179.     int nOldSize = m_nSize;
  180.     SetSize(m_nSize + src.m_nSize);
  181.  
  182.     CopyElements(m_pData + nOldSize, src.m_pData, src.m_nSize);
  183.  
  184.     return nOldSize;
  185. }
  186.  
  187. void CStringArray::Copy(const CStringArray& src)
  188. {
  189.     ASSERT_VALID(this);
  190.     ASSERT(this != &src);   // cannot append to itself
  191.  
  192.     SetSize(src.m_nSize);
  193.  
  194.     CopyElements(m_pData, src.m_pData, src.m_nSize);
  195.  
  196. }
  197.  
  198. void CStringArray::FreeExtra()
  199. {
  200.     ASSERT_VALID(this);
  201.  
  202.     if (m_nSize != m_nMaxSize)
  203.     {
  204.         // shrink to desired size
  205. #ifdef SIZE_T_MAX
  206.         ASSERT(m_nSize <= SIZE_T_MAX/sizeof(CString)); // no overflow
  207. #endif
  208.         CString* pNewData = NULL;
  209.         if (m_nSize != 0)
  210.         {
  211.             pNewData = (CString*) new BYTE[m_nSize * sizeof(CString)];
  212.             // copy new data from old
  213.             memcpy(pNewData, m_pData, m_nSize * sizeof(CString));
  214.         }
  215.  
  216.         // get rid of old stuff (note: no destructors called)
  217.         delete[] (BYTE*)m_pData;
  218.         m_pData = pNewData;
  219.         m_nMaxSize = m_nSize;
  220.     }
  221. }
  222.  
  223. /////////////////////////////////////////////////////////////////////////////
  224.  
  225. void CStringArray::SetAtGrow(int nIndex, LPCTSTR newElement)
  226. {
  227.     ASSERT_VALID(this);
  228.     ASSERT(nIndex >= 0);
  229.  
  230.     if (nIndex >= m_nSize)
  231.         SetSize(nIndex+1);
  232.     m_pData[nIndex] = newElement;
  233. }
  234.  
  235.  
  236. void CStringArray::SetAtGrow(int nIndex, const CString& newElement)
  237. {
  238.     ASSERT_VALID(this);
  239.     ASSERT(nIndex >= 0);
  240.  
  241.     if (nIndex >= m_nSize)
  242.         SetSize(nIndex+1);
  243.     m_pData[nIndex] = newElement;
  244. }
  245.  
  246.  
  247.  
  248. void CStringArray::InsertEmpty(int nIndex, int nCount)
  249. {
  250.     ASSERT_VALID(this);
  251.     ASSERT(nIndex >= 0);    // will expand to meet need
  252.     ASSERT(nCount > 0);     // zero or negative size not allowed
  253.  
  254.     if (nIndex >= m_nSize)
  255.     {
  256.         // adding after the end of the array
  257.         SetSize(nIndex + nCount);  // grow so nIndex is valid
  258.     }
  259.     else
  260.     {
  261.         // inserting in the middle of the array
  262.         int nOldSize = m_nSize;
  263.         SetSize(m_nSize + nCount);  // grow it to new size
  264.         // shift old data up to fill gap
  265.         memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  266.             (nOldSize-nIndex) * sizeof(CString));
  267.  
  268.         // re-init slots we copied from
  269.  
  270.         ConstructElements(&m_pData[nIndex], nCount);
  271.  
  272.     }
  273.  
  274.     // insert new value in the gap
  275.     ASSERT(nIndex + nCount <= m_nSize);
  276. }
  277.  
  278.  
  279. void CStringArray::InsertAt(int nIndex, LPCTSTR newElement, int nCount)
  280. {
  281.  
  282.     // make room for new elements
  283.     InsertEmpty(nIndex, nCount);
  284.  
  285.  
  286.  
  287.     // copy elements into the empty space
  288.     CString temp = newElement;
  289.     while (nCount--)
  290.         m_pData[nIndex++] = temp;
  291.  
  292. }
  293.  
  294.  
  295. void CStringArray::InsertAt(int nIndex, const CString& newElement, int nCount)
  296. {
  297.     // make room for new elements
  298.     InsertEmpty(nIndex, nCount);
  299.  
  300.     // copy elements into the empty space
  301.     while (nCount--)
  302.         m_pData[nIndex++] = newElement;
  303. }
  304.  
  305.  
  306. void CStringArray::RemoveAt(int nIndex, int nCount)
  307. {
  308.     ASSERT_VALID(this);
  309.     ASSERT(nIndex >= 0);
  310.     ASSERT(nCount >= 0);
  311.     ASSERT(nIndex + nCount <= m_nSize);
  312.  
  313.     // just remove a range
  314.     int nMoveCount = m_nSize - (nIndex + nCount);
  315.  
  316.     DestructElements(&m_pData[nIndex], nCount);
  317.  
  318.     if (nMoveCount)
  319.         memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
  320.             nMoveCount * sizeof(CString));
  321.     m_nSize -= nCount;
  322. }
  323.  
  324. void CStringArray::InsertAt(int nStartIndex, CStringArray* pNewArray)
  325. {
  326.     ASSERT_VALID(this);
  327.     ASSERT(pNewArray != NULL);
  328.     ASSERT_KINDOF(CStringArray, pNewArray);
  329.     ASSERT_VALID(pNewArray);
  330.     ASSERT(nStartIndex >= 0);
  331.  
  332.     if (pNewArray->GetSize() > 0)
  333.     {
  334.         InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  335.         for (int i = 0; i < pNewArray->GetSize(); i++)
  336.             SetAt(nStartIndex + i, pNewArray->GetAt(i));
  337.     }
  338. }
  339.  
  340.  
  341. /////////////////////////////////////////////////////////////////////////////
  342. // Serialization
  343.  
  344. void CStringArray::Serialize(CArchive& ar)
  345. {
  346.     ASSERT_VALID(this);
  347.  
  348.     CObject::Serialize(ar);
  349.  
  350.     if (ar.IsStoring())
  351.     {
  352.         ar.WriteCount(m_nSize);
  353.         for (int i = 0; i < m_nSize; i++)
  354.             ar << m_pData[i];
  355.     }
  356.     else
  357.     {
  358.         DWORD nOldSize = ar.ReadCount();
  359.         SetSize(nOldSize);
  360.         for (int i = 0; i < m_nSize; i++)
  361.             ar >> m_pData[i];
  362.     }
  363. }
  364.  
  365.  
  366.  
  367. /////////////////////////////////////////////////////////////////////////////
  368. // Diagnostics
  369.  
  370. #ifdef _DEBUG
  371. void CStringArray::Dump(CDumpContext& dc) const
  372. {
  373.     CObject::Dump(dc);
  374.  
  375.     dc << "with " << m_nSize << " elements";
  376.     if (dc.GetDepth() > 0)
  377.     {
  378.         for (int i = 0; i < m_nSize; i++)
  379.             dc << "\n\t[" << i << "] = " << m_pData[i];
  380.     }
  381.  
  382.     dc << "\n";
  383. }
  384.  
  385. void CStringArray::AssertValid() const
  386. {
  387.     CObject::AssertValid();
  388.  
  389.     if (m_pData == NULL)
  390.     {
  391.         ASSERT(m_nSize == 0);
  392.         ASSERT(m_nMaxSize == 0);
  393.     }
  394.     else
  395.     {
  396.         ASSERT(m_nSize >= 0);
  397.         ASSERT(m_nMaxSize >= 0);
  398.         ASSERT(m_nSize <= m_nMaxSize);
  399.         ASSERT(AfxIsValidAddress(m_pData, m_nMaxSize * sizeof(CString)));
  400.     }
  401. }
  402. #endif //_DEBUG
  403.  
  404. #ifdef AFX_INIT_SEG
  405. #pragma code_seg(AFX_INIT_SEG)
  406. #endif
  407.  
  408.  
  409. IMPLEMENT_SERIAL(CStringArray, CObject, 0)
  410.  
  411. /////////////////////////////////////////////////////////////////////////////
  412.