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 {
135 // load set
136
137 // first, delete old set
138 ScratchAll();
139
140 int nCount;
141 // load cardinality
142 ar >> nCount;
143 // load all elements
144 for (int i=0; i<nCount; i++)
145 {
146 C* element;
147 ar >> element;
148 Insert(element);
149 delete element;
150 }
151 }
152 }
153
154
155 // invariance
156 template<class C> void CPolymorphicSet<C>::AssertValid() const
157 {
158 CObject::AssertValid();
159
160 // if the set is empty then cursor must be NULL
161 if (m_Set.IsEmpty())
162 {
163 ASSERT(m_Cursor == NULL);
164 return;
165 }
166
167 // each element may be present in set at most once
168 // cursor must point to an element
169 POSITION pos = m_Set.GetHeadPosition();
170 bool bValidCursor = false;
171 while (pos != NULL)
172 {
173 // element that the cursor points to was found ?
174 if (pos == m_Cursor)
175 bValidCursor = true;
176
177 // get element
178 C* element = m_Set.GetNext(pos);
179 POSITION posfind = pos;
180 // compare to the remaining elements
181 while (posfind != NULL)
182 {
183 C* compare = m_Set.GetNext(posfind);
184 // no two equal elements are allowed
185 ASSERT(!(*element == *compare));
186 }
187 }
188
189 // cursor validated ?
190 ASSERT(bValidCursor);
191 }
192
193
194 // dump
195 template<class C> void CPolymorphicSet<C>::Dump(CDumpContext& dc) const
196 {
197 CObject::Dump(dc);
198
199 dc << Card() << " elements, cursor points to " << m_Cursor << "\n";
200
201 POSITION pos = m_Set.GetHeadPosition();
202 while (pos != NULL)
203 dc << m_Set.GetNext(pos) << "\n";
204 }
205
206
207 // copy the whole set
208 template<class C> CPolymorphicSet<C>& CPolymorphicSet<C>::operator=(const CPolymorphicSet<C>& set)
209 {
210 // delete old elements
211 m_Set.RemoveAll();
212
213 POSITION pos = set.m_Set.GetHeadPosition();
214 while (pos != NULL)
215 {
216 // save current position
217 POSITION cursor = pos;
218
219 // clone each element
220 C* element = set.m_Set.GetNext(pos);
221 C* copy = Clone(element);
222 m_Set.AddTail(copy);
223
224 // set cursor
225 // we can't use set.m_Cursor directly because we copied all elements
226 // and therefore lost their old memory address
227 if (cursor == set.m_Cursor)
228 m_Cursor = m_Set.GetTailPosition();
229 }
230
231 return *this;
232 }
233
234
235 // see operator=
236 template<class C> CPolymorphicSet<C>& CPolymorphicSet<C>::Copy(const CPolymorphicSet<C>& set)
237 {
238 return operator=(set);
239 }
240
241
242 // compare two sets
243 template<class C> bool CPolymorphicSet<C>::operator==(const CPolymorphicSet<C>& set) const
244 {
245 // the cursors may differ !
246
247 // same number of elements is required
248 if (m_Set.GetCount() != set.m_Set.GetCount())
249 return false;
250
251 // each element of this set must be found in the other set
252 POSITION pos = m_Set.GetHeadPosition();
253 while (pos != NULL)
254 {
255 C* element = m_Set.GetNext(pos);
256 if (!set.m_Set.Find(element))
257 return false;
258 }
259
260 // all elements were found, sets must be equal
261 return true;
262 }
263
264
265 // see operator==
266 template<class C> bool CPolymorphicSet<C>::EqualValue(const CPolymorphicSet<C>& set) const
267 {
268 return operator==(set);
269 }
270
271
272 // object identity
273 template<class C> bool CPolymorphicSet<C>::Equal(const CPolymorphicSet<C>* set) const
274 {
275 return (set == this);
276 }
277
278
279 // returns number of stored elements
280 template<class C> int CPolymorphicSet<C>::Card() const
281 {
282 return m_Set.GetCount();
283 }
284
285
286 // first stored element
287 template<class C> C* CPolymorphicSet<C>::GetFirst()
288 {
289 // set must not be empty
290 ASSERT(!m_Set.IsEmpty());
291
292 // set cursor
293 m_Cursor = m_Set.GetHeadPosition();
294
295 // clone first element
296 return GetCurrent();
297 }
298
299
300 // next element
301 template<class C> C* CPolymorphicSet<C>::GetNext()
302 {
303 // set must not be empty
304 ASSERT(!m_Set.IsEmpty());
305 // cursor must not be at the end of the set
306 ASSERT(m_Cursor != NULL);
307
308 // set cursor
309 m_Set.GetNext(m_Cursor);
310
311 // clone element
312 return GetCurrent();
313 }
314
315
316 // gets the element the cursor points to
317 template<class C> C* CPolymorphicSet<C>::GetCurrent() const
318 {
319 // cursor must not be at the end of the set
320 ASSERT(m_Cursor != NULL);
321
322 // generate copy
323 C* copy = Clone(m_Set.GetAt(m_Cursor));
324
325 return copy;
326 }
327
328
329 // inserts an element
330 template<class C> int CPolymorphicSet<C>::Insert(const C* element)
331 {
332 // don't insert an object twice
333 if (Find(element))
334 return -1;
335
336 // add a copy to our set, change cursor
337 m_Cursor = m_Set.AddTail(Clone(element));
338
339 // return index in the set
340 return m_Set.GetCount()-1;
341 }
342
343
344 // deletes current element
345 template<class C> void CPolymorphicSet<C>::Scratch()
346 {
347 // cursor must not be at the end of the set
348 ASSERT(m_Cursor != NULL);
349
350 // store current cursor
351 POSITION removepos = m_Cursor;
352 // go on to the next element (else we lose it after erasing this element)
353 m_Set.GetNext(m_Cursor);
354
355 // remove element the cursor pointed to previously
356 delete m_Set.GetAt(removepos);
357 m_Set.RemoveAt(removepos);
358 }
359
360
361 // looks for an element
362 template<class C> bool CPolymorphicSet<C>::Find(const C* element)
363 {
364 // only non-empty sets
365 if (m_Set.IsEmpty())
366 return false;
367
368 // iterate through the whole list
369 POSITION pos = m_Set.GetHeadPosition();
370 while (pos != NULL)
371 {
372 // store position in case we find a match
373 POSITION storepos = pos;
374
375 // get an element we compare to
376 C* compare = m_Set.GetNext(pos);
377 // equal ?
378 if (*element == *compare)
379 {
380 // yes, set cursor and return "success !"
381 m_Cursor = storepos;
382 return true;
383 }
384 }
385
386 // element is not part of the set
387 return false;
388 }
389
390
391 // creates a new instance and copies all attributes
392 template<class C> C* CPolymorphicSet<C>::Clone(const C* element) const
393 {
394 // create new instance (care for correct class !)
395 C* copy = (C*)element->GetRuntimeClass()->CreateObject();
396 // copy attributes
397 *copy = *element;
398
399 return copy;
400 }
401
402
403 // deletes the whole set
404 template<class C> void CPolymorphicSet<C>::ScratchAll()
405 {
406 while (!m_Set.IsEmpty())
407 {
408 delete m_Set.GetHead();
409 m_Set.RemoveHead();
410 }
411 }
412
413
414 #endif // !defined(AFX_POLYMORPHICSET_H__BA324DAE_872B_11D5_9BB8_AB7BB57BD00C__INCLUDED_)
415