|
|
1.1 root 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.