1 ///////////////////////////////////////////////////////////
2 // Softwarebauelemente II, C2.1
3 //
4 // A template for polymorphic set - designed in MFC-style
5 // The only parameter is the base class of all elements
6 // (at least CObject)
7 // All elements are copied by the interface methods
8 // to avoid unexpected behaviour (e.g. external erase)
9 //
10 // author: Stephan Brumme
11 // last changes: August 3, 2001
12
13 #if !defined(AFX_POLYMORPHICSET_H__BA324DAE_872B_11D5_9BB8_AB7BB57BD00C__INCLUDED_)
14 #define AFX_POLYMORPHICSET_H__BA324DAE_872B_11D5_9BB8_AB7BB57BD00C__INCLUDED_
15
16
17 #include "stdafx.h"
18
19
20 #if _MSC_VER > 1000
21 #pragma once
22 #endif // _MSC_VER > 1000
23
24
25 template<class C> class CPolymorphicSet : public CObject
26 {
27 public:
28 // default constructor
29 CPolymorphicSet();
30 // copy constructor
31 CPolymorphicSet(const CPolymorphicSet<C>& set);
32
33 // destructor
34 virtual ~CPolymorphicSet();
35
36 // serialization
37 virtual void Serialize(CArchive &ar);
38 // invariance
39 virtual void AssertValid() const;
40 // dump
41 virtual void Dump(CDumpContext& dc) const;
42
43 // copy the whole set
44 virtual CPolymorphicSet<C>& operator=(const CPolymorphicSet<C>& set);
45 virtual CPolymorphicSet<C>& Copy (const CPolymorphicSet<C>& set);
46 // compare two sets
47 // value identity
48 virtual bool operator==(const CPolymorphicSet<C>& set) const;
49 virtual bool EqualValue(const CPolymorphicSet<C>& set) const;
50 // object identity
51 virtual bool Equal (const CPolymorphicSet<C>* set) const;
52
53 // returns number of stored elements
54 int Card() const;
55
56 // first stored element
57 C* GetFirst();
58 // next element
59 C* GetNext();
60 // gets the element the cursor points to
61 C* GetCurrent() const;
62
63 // inserts an element
64 int Insert(const C* element);
65 // deletes current element
66 void Scratch();
67 // finds an element
68 bool Find(const C* element);
69
70 protected:
71 // creates a new instance and copies all attributes
72 C* Clone(const C* element) const;
73
74 // deletes the whole set
75 void ScratchAll();
76
77 // stores all elements in a list
78 CList<C*, C*> m_Set;
79 // cursor, may be altered at any time
80 POSITION m_Cursor;
81
82 };
83
84
85 ///////////////////////////////////////////////////////////
86 ///////////////////////////////////////////////////////////
87 ///////////////////////////////////////////////////////////
88
89
90 // default constructor
91 template<class C> CPolymorphicSet<C>::CPolymorphicSet()
92 {
93 // empty set
94 m_Cursor = NULL;
95 }
96
97
98 // copy constructor
99 template<class C> CPolymorphicSet<C>::CPolymorphicSet(const CPolymorphicSet<C>& set)
100 {
101 operator=(set);
102 m_Cursor = m_Set.GetHeadPosition();
103 }
104
105
106 // destructor
107 template<class C> CPolymorphicSet<C>::~CPolymorphicSet()
108 {
109 ScratchAll();
110 }
111
112
113 // serialization
114 template<class C> void CPolymorphicSet<C>::Serialize(CArchive &ar)
115 {
116 // do not forget to serialize CObject's data members
117 CObject::Serialize(ar);
118
119 // make use of CArchive's overloaded << and >> operators for *CObject
120
121 if (ar.IsStoring())
122 {
123 // save the set
124
125 // write cardinality
126 ar << m_Set.GetCount();
127
128 // write all elements
129 POSITION pos = m_Set.GetHeadPosition();
130 while (pos != NULL)
131 ar << m_Set.GetNext(pos);
132 }
133 else
{
134 // load set
135
136 // first, delete old set
137 ScratchAll();
138
139 int nCount;
140 // load cardinality
141 ar >> nCount;
142 // load all elements
143 for (int i=0; i<nCount; i++)
144 {
145 C* element;
146 ar >> element;
147 Insert(element);
148 delete element;
149 }
150 }
151 }
152
153
154 // invariance
155 template<class C> void CPolymorphicSet<C>::AssertValid() const
{
156 CObject::AssertValid();
157
158 // if the set is empty then cursor must be NULL
159 if (m_Set.IsEmpty())
160 {
161 ASSERT(m_Cursor == NULL);
162 return;
163 }
164
165 // each element may be present in set at most once
166 // cursor must point to an element
167 POSITION pos = m_Set.GetHeadPosition();
168 bool bValidCursor = false;
169 while (pos != NULL)
170 {
171 // element that the cursor points to was found ?
172 if (pos == m_Cursor)
173 bValidCursor = true;
174
175 // get element
176 C* element = m_Set.GetNext(pos);
177 POSITION posfind = pos;
178 // compare to the remaining elements
179 while (posfind != NULL)
180 {
181 C* compare = m_Set.GetNext(posfind);
182 // no two equal elements are allowed
183 ASSERT(!(*element == *compare));
184 }
185 }
186
187 // cursor validated ?
188 ASSERT(bValidCursor);
189 }
190
191
192 // dump
193 template<class C> void CPolymorphicSet<C>::Dump(CDumpContext& dc) const
{
194 CObject::Dump(dc);
195
196 dc << Card() << " elements, cursor points to " << m_Cursor << "\n";
197
198 POSITION pos = m_Set.GetHeadPosition();
199 while (pos != NULL)
200 dc << m_Set.GetNext(pos) << "\n";
201 }
202
203
204 // copy the whole set
205 template<class C> CPolymorphicSet<C>& CPolymorphicSet<C>::operator=(const CPolymorphicSet<C>& set)
206 {
207 // delete old elements
208 m_Set.RemoveAll();
209
210 POSITION pos = set.m_Set.GetHeadPosition();
211 while (pos != NULL)
212 {
213 // save current position
214 POSITION cursor = pos;
215
216 // clone each element
217 C* element = set.m_Set.GetNext(pos);
218 C* copy = Clone(element);
219 m_Set.AddTail(copy);
220
221 // set cursor
222 // we can't use set.m_Cursor directly because we copied all elements
223 // and therefore lost their old memory address
224 if (cursor == set.m_Cursor)
225 m_Cursor = m_Set.GetTailPosition();
226 }
227
228 return *this;
229 }
230
231
232 // see operator=
233 template<class C> CPolymorphicSet<C>& CPolymorphicSet<C>::Copy(const CPolymorphicSet<C>& set)
234 {
235 return operator=(set);
236 }
237
238
239 // compare two sets
240 template<class C> bool CPolymorphicSet<C>::operator==(const CPolymorphicSet<C>& set) const
{
241 // the cursors may differ !
242
243 // same number of elements is required
244 if (m_Set.GetCount() != set.m_Set.GetCount())
245 return false;
246
247 // each element of this set must be found in the other set
248 POSITION pos = m_Set.GetHeadPosition();
249 while (pos != NULL)
250 {
251 C* element = m_Set.GetNext(pos);
252 if (!set.m_Set.Find(element))
253 return false;
254 }
255
256 // all elements were found, sets must be equal
257 return true;
258 }
259
260
261 // see operator==
262 template<class C> bool CPolymorphicSet<C>::EqualValue(const CPolymorphicSet<C>& set) const
{
263 return operator==(set);
264 }
265
266
267 // object identity
268 template<class C> bool CPolymorphicSet<C>::Equal(const CPolymorphicSet<C>* set) const
{
269 return (set == this);
270 }
271
272
273 // returns number of stored elements
274 template<class C> int CPolymorphicSet<C>::Card() const
{
275 return m_Set.GetCount();
276 }
277
278
279 // first stored element
280 template<class C> C* CPolymorphicSet<C>::GetFirst()
281 {
282 // set must not be empty
283 ASSERT(!m_Set.IsEmpty());
284
285 // set cursor
286 m_Cursor = m_Set.GetHeadPosition();
287
288 // clone first element
289 return GetCurrent();
290 }
291
292
293 // next element
294 template<class C> C* CPolymorphicSet<C>::GetNext()
295 {
296 // set must not be empty
297 ASSERT(!m_Set.IsEmpty());
298 // cursor must not be at the end of the set
299 ASSERT(m_Cursor != NULL);
300
301 // set cursor
302 m_Set.GetNext(m_Cursor);
303
304 // clone element
305 return GetCurrent();
306 }
307
308
309 // gets the element the cursor points to
310 template<class C> C* CPolymorphicSet<C>::GetCurrent() const
{
311 // cursor must not be at the end of the set
312 ASSERT(m_Cursor != NULL);
313
314 // generate copy
315 C* copy = Clone(m_Set.GetAt(m_Cursor));
316
317 return copy;
318 }
319
320
321 // inserts an element
322 template<class C> int CPolymorphicSet<C>::Insert(const C* element)
323 {
324 // don't insert an object twice
325 if (Find(element))
326 return -1;
327
328 // add a copy to our set, change cursor
329 m_Cursor = m_Set.AddTail(Clone(element));
330
331 // return index in the set
332 return m_Set.GetCount()-1;
333 }
334
335
336 // deletes current element
337 template<class C> void CPolymorphicSet<C>::Scratch()
338 {
339 // cursor must not be at the end of the set
340 ASSERT(m_Cursor != NULL);
341
342 // store current cursor
343 POSITION removepos = m_Cursor;
344 // go on to the next element (else we lose it after erasing this element)
345 m_Set.GetNext(m_Cursor);
346
347 // remove element the cursor pointed to previously
348 delete m_Set.GetAt(removepos);
349 m_Set.RemoveAt(removepos);
350 }
351
352
353 // looks for an element
354 template<class C> bool CPolymorphicSet<C>::Find(const C* element)
355 {
356 // only non-empty sets
357 if (m_Set.IsEmpty())
358 return false;
359
360 // iterate through the whole list
361 POSITION pos = m_Set.GetHeadPosition();
362 while (pos != NULL)
363 {
364 // store position in case we find a match
365 POSITION storepos = pos;
366
367 // get an element we compare to
368 C* compare = m_Set.GetNext(pos);
369 // equal ?
370 if (*element == *compare)
371 {
372 // yes, set cursor and return "success !"
373 m_Cursor = storepos;
374 return true;
375 }
376 }
377
378 // element is not part of the set
379 return false;
380 }
381
382
383 // creates a new instance and copies all attributes
384 template<class C> C* CPolymorphicSet<C>::Clone(const C* element) const
{
385 // create new instance (care for correct class !)
386 C* copy = (C*)element->GetRuntimeClass()->CreateObject();
387 // copy attributes
388 *copy = *element;
389
390 return copy;
391 }
392
393
394 // deletes the whole set
395 template<class C> void CPolymorphicSet<C>::ScratchAll()
396 {
397 while (!m_Set.IsEmpty())
398 {
399 delete m_Set.GetHead();
400 m_Set.RemoveHead();
401 }
402 }
403
404
405 #endif // !defined(AFX_POLYMORPHICSET_H__BA324DAE_872B_11D5_9BB8_AB7BB57BD00C__INCLUDED_)
406
407