]> Dogcows Code - chaz/yoink/blob - src/stlplus/containers/safe_iterator.tpp
fixed documentation about where to find licenses
[chaz/yoink] / src / stlplus / containers / safe_iterator.tpp
1 namespace stlplus
2 {
3
4 ////////////////////////////////////////////////////////////////////////////////
5 // body class implements the aliasing behaviour
6
7 template<typename O, typename N>
8 class safe_iterator_body
9 {
10 private:
11 const O* m_owner;
12 N* m_node;
13 unsigned m_count;
14
15 public:
16
17 safe_iterator_body(const O* owner, N* node) throw() :
18 m_owner(owner), m_node(node), m_count(1)
19 {
20 }
21
22 ~safe_iterator_body(void) throw()
23 {
24 m_owner = 0;
25 m_node = 0;
26 }
27
28 unsigned count(void) const
29 {
30 return m_count;
31 }
32
33 void increment(void)
34 {
35 ++m_count;
36 }
37
38 bool decrement(void)
39 {
40 --m_count;
41 return m_count == 0;
42 }
43
44 N* node(void) const throw()
45 {
46 return m_node;
47 }
48
49 const O* owner(void) const throw()
50 {
51 return m_owner;
52 }
53
54 void change_owner(const O* owner)
55 {
56 m_owner = owner;
57 }
58
59 bool equal(const safe_iterator_body<O,N>* right) const throw()
60 {
61 return m_node == right->m_node;
62 }
63
64 int compare(const safe_iterator_body<O,N>* right) const throw()
65 {
66 if (m_node == right->m_node) return 0;
67 return (m_node < right->m_node) ? -1 : 1;
68 }
69
70 bool null(void) const throw()
71 {
72 return m_owner == 0;
73 }
74
75 bool end(void) const throw()
76 {
77 return m_owner != 0 && m_node == 0;
78 }
79
80 bool valid(void) const throw()
81 {
82 return m_owner != 0 && m_node != 0;
83 }
84
85 void set_end(void) throw()
86 {
87 m_node = 0;
88 }
89
90 void set_null(void) throw()
91 {
92 m_owner = 0;
93 m_node = 0;
94 }
95
96 void assert_valid(void) const throw(null_dereference,end_dereference)
97 {
98 if (null())
99 throw null_dereference("stlplus::safe_iterator: dereferencing null iterator");
100 if (end())
101 throw end_dereference("stlplus::safe_iterator: dereferencing end iterator");
102 }
103
104 void assert_non_null(void) const throw(null_dereference)
105 {
106 if (null())
107 throw null_dereference("stlplus::safe_iterator: dereferencing null iterator");
108 }
109
110 void assert_owner(const O* owner) const throw(wrong_object)
111 {
112 if (owner != m_owner)
113 throw wrong_object("stlplus::safe_iterator: using iterator with wrong object");
114 }
115 };
116
117
118 ////////////////////////////////////////////////////////////////////////////////
119 // Master Iterator
120 ////////////////////////////////////////////////////////////////////////////////
121
122 // construct a valid iterator
123 template<typename O, typename N>
124 master_iterator<O,N>::master_iterator(const O* owner, N* node) throw() :
125 m_body(new safe_iterator_body<O,N>(owner,node))
126 {
127 }
128
129 // destructor - disconnect all iterators from the node
130 // this usually happens when the node is deleted and must invalidate all aliases
131 template<typename O, typename N>
132 master_iterator<O,N>::~master_iterator(void) throw()
133 {
134 m_body->set_end();
135 if(m_body->decrement())
136 {
137 delete m_body;
138 m_body = 0;
139 }
140 }
141
142 // dereference
143 template<typename O, typename N>
144 N* master_iterator<O,N>::node(void) const throw()
145 {
146 return m_body->node();
147 }
148
149 template<typename O, typename N>
150 const O* master_iterator<O,N>::owner(void) const throw()
151 {
152 return m_body->owner();
153 }
154
155 // when you move a node from one owner to another, call this on the node's iterator
156 // this effectively moves all iterators to the node so that they are owned by the new owner too
157 template<typename O, typename N>
158 void master_iterator<O,N>::change_owner(const O* owner) throw()
159 {
160 m_body->change_owner(owner);
161 }
162
163 ////////////////////////////////////////////////////////////////////////////////
164 // Safe Iterator
165 ////////////////////////////////////////////////////////////////////////////////
166
167 // construct a null iterator
168 // later assignment of a valid iterator to this is done by using step
169 template<typename O, typename N>
170 safe_iterator<O,N>::safe_iterator(void) throw() :
171 m_body(new safe_iterator_body<O,N>(0,0))
172 {
173 }
174
175 // construct a valid iterator by aliasing from the owner node's master iterator
176 template<typename O, typename N>
177 safe_iterator<O,N>::safe_iterator(const master_iterator<O,N>& r) throw() :
178 m_body(0)
179 {
180 m_body = r.m_body;
181 m_body->increment();
182 }
183
184 // construct a valid iterator by aliasing from the owner node's master iterator
185 template<typename O, typename N>
186 safe_iterator<O,N>::safe_iterator(const safe_iterator<O,N>& r) throw() :
187 m_body(0)
188 {
189 m_body = r.m_body;
190 m_body->increment();
191 }
192
193 // assignment implements dealiasing followed by aliasing
194 template<typename O, typename N>
195 safe_iterator<O,N>& safe_iterator<O,N>::operator=(const safe_iterator<O,N>& r) throw()
196 {
197 if (m_body != r.m_body)
198 {
199 if (m_body->decrement())
200 delete m_body;
201 m_body = r.m_body;
202 m_body->increment();
203 }
204 return *this;
205 }
206
207 // destructor - implements dealiasing
208 template<typename O, typename N>
209 safe_iterator<O,N>::~safe_iterator(void) throw()
210 {
211 if(m_body->decrement())
212 {
213 delete m_body;
214 m_body = 0;
215 }
216 }
217
218
219 // increment/decrement operation
220 // implements dealiasing followed by aliasing
221 template<typename O, typename N>
222 void safe_iterator<O,N>::set(const master_iterator<O,N>& r) throw()
223 {
224 if (m_body != r.m_body)
225 {
226 if (m_body->decrement())
227 delete m_body;
228 m_body = r.m_body;
229 m_body->increment();
230 }
231 }
232
233 // dereference
234 template<typename O, typename N>
235 N* safe_iterator<O,N>::node(void) const throw()
236 {
237 return m_body->node();
238 }
239
240 template<typename O, typename N>
241 const O* safe_iterator<O,N>::owner(void) const throw()
242 {
243 return m_body->owner();
244 }
245
246 // change to a null iterator - i.e. one that doees not belong to any object
247 // this does not affect any other iterators pointing to the same node
248 template<typename O, typename N>
249 void safe_iterator<O,N>::set_null(void) throw()
250 {
251 if (m_body->count() == 1)
252 {
253 // no aliases, so just make this null
254 m_body->set_null();
255 }
256 else
257 {
258 // create a new body which is null so as not to affect any other aliases
259 m_body->decrement();
260 m_body = new safe_iterator_body<O,N>(0,0);
261 }
262 }
263
264 ////////////////////////////////////////////////////////////////////////////////
265 // operations for clients that do not have a master end iterator
266 // alternatively, have a master end iterator as part of the container
267 // and call constructor(master_end) or step(master_end)
268
269 // construct an end iterator
270 template<typename O, typename N>
271 safe_iterator<O,N>::safe_iterator(const O* owner) throw() :
272 m_body(new safe_iterator_body<O,N>(owner,0))
273 {
274 }
275
276 // change to an end iterator - e.g. as a result of incrementing off the end
277 template<typename O, typename N>
278 void safe_iterator<O,N>::set_end(void) throw()
279 {
280 if (m_body->count() == 1)
281 {
282 // no aliases, so just make this an end iterator
283 m_body->set_end();
284 }
285 else
286 {
287 // create a new body which is null so as not to affect any other aliases
288 m_body->decrement();
289 m_body = new safe_iterator_body<O,N>(owner(),0);
290 }
291 }
292
293 ////////////////////////////////////////////////////////////////////////////////
294 // tests
295
296 // comparison
297 template<typename O, typename N>
298 bool safe_iterator<O,N>::equal(const safe_iterator<O,N>& right) const throw()
299 {
300 if (m_body == right.m_body) return true;
301 return m_body->equal(right.m_body);
302 }
303
304 template<typename O, typename N>
305 int safe_iterator<O,N>::compare(const safe_iterator<O,N>& right) const throw()
306 {
307 return m_body->compare(right.m_body);
308 }
309
310 // a null iterator is one that has not been initialised with a value yet
311 template<typename O, typename N>
312 bool safe_iterator<O,N>::null(void) const throw()
313 {
314 return m_body->null();
315 }
316
317 // an end iterator is one that points to the end element of the list of nodes
318 template<typename O, typename N>
319 bool safe_iterator<O,N>::end(void) const throw()
320 {
321 return m_body->end();
322 }
323
324 // a valid iterator is one that can be dereferenced
325 template<typename O, typename N>
326 bool safe_iterator<O,N>::valid(void) const throw()
327 {
328 return m_body->valid();
329 }
330
331 // check the rules for a valid iterator that can be dereferenced
332 template<typename O, typename N>
333 void safe_iterator<O,N>::assert_valid(void) const throw(null_dereference,end_dereference)
334 {
335 m_body->assert_valid();
336 }
337
338 template<typename O, typename N>
339 void safe_iterator<O,N>::assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference)
340 {
341 m_body->assert_valid();
342 m_body->assert_owner(owner);
343 }
344
345 template<typename O, typename N>
346 void safe_iterator<O,N>::assert_non_null(void) const throw(null_dereference)
347 {
348 m_body->assert_non_null();
349 }
350
351 template<typename O, typename N>
352 void safe_iterator<O,N>::assert_owner(const O* owner) const throw(wrong_object)
353 {
354 m_body->assert_owner(owner);
355 }
356
357 } // end namespace stlplus
This page took 0.053523 seconds and 5 git commands to generate.