home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK8 / MFC / SAMPLES / TEMPLDEF / ARRAY.CT$ / array
Encoding:
Text File  |  1992-03-03  |  11.2 KB  |  430 lines

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