1/*
2    File:       CArrayIterator.cpp
3
4    Contains:   Implementation of the CArrayIterator class
5
6
7*/
8
9#include "CDynamicArray.h"
10#include "CArrayIterator.h"
11
12//--------------------------------------------------------------------------------
13#define super OSObject
14    OSDefineMetaClassAndStructors(CArrayIterator, OSObject);
15//--------------------------------------------------------------------------------
16
17
18//--------------------------------------------------------------------------------
19//      CArrayIterator::SwitchArray
20//--------------------------------------------------------------------------------
21void CArrayIterator::SwitchArray(CDynamicArray* newArray, Boolean itsForward)
22{
23    // switch from one array to another
24    XASSERT(newArray);
25
26    if (fDynamicArray)
27	{
28	fDynamicArray->fIterator = RemoveFromList();
29	fDynamicArray = nil;
30	}
31
32    init(newArray, 0, newArray->fSize - 1, itsForward);
33
34} // CArrayIterator::SwitchArray
35
36
37//--------------------------------------------------------------------------------
38//      CArrayIterator::AppendToList
39//--------------------------------------------------------------------------------
40CArrayIterator* CArrayIterator::AppendToList(CArrayIterator* toList)
41{
42    if (toList)
43	{
44	fNextLink = toList->fNextLink;
45	fPreviousLink = toList;
46
47	fNextLink->fPreviousLink = this;
48	toList->fNextLink = this;
49	}
50    return this;
51
52} // CArrayIterator::AppendToList
53
54
55//--------------------------------------------------------------------------------
56//      CArrayIterator::RemoveFromList
57//--------------------------------------------------------------------------------
58CArrayIterator* CArrayIterator::RemoveFromList()
59{
60    CArrayIterator * returnLink;
61
62    if (fNextLink == this)
63	returnLink = nil;
64    else
65	returnLink = fNextLink;
66
67    fNextLink->fPreviousLink = fPreviousLink;
68    fPreviousLink->fNextLink = fNextLink;
69
70    fNextLink = this;
71    fPreviousLink = this;
72
73    return returnLink;
74
75} // CArrayIterator::RemoveFromList
76
77
78//--------------------------------------------------------------------------------
79//      CArrayIterator::CArrayIterator(void)
80//--------------------------------------------------------------------------------
81CArrayIterator *
82CArrayIterator::cArrayIterator()
83{
84    CArrayIterator *obj = new CArrayIterator;
85
86    if (obj && !obj->init()) {
87	obj->release();
88	obj = nil;
89    }
90    return obj;
91
92} // CArrayIterator::CArrayIterator
93
94//--------------------------------------------------------------------------------
95//      CArrayIterator::cArrayIterator(1)
96//--------------------------------------------------------------------------------
97CArrayIterator *
98CArrayIterator::cArrayIterator(CDynamicArray* itsDynamicArray)
99{
100    CArrayIterator *obj = new CArrayIterator;
101
102    XASSERT(itsDynamicArray);
103    // rely on Init to sanity check array bounds
104
105    if (obj && !obj->init(itsDynamicArray)) {
106	obj->release();
107	obj = nil;
108    }
109    return obj;
110
111} // CArrayIterator::CArrayIterator
112
113//--------------------------------------------------------------------------------
114//      CArrayIterator::cArrayIterator(2)
115//--------------------------------------------------------------------------------
116CArrayIterator *
117CArrayIterator::cArrayIterator(CDynamicArray* itsDynamicArray, Boolean itsForward)
118{
119    CArrayIterator *obj = new CArrayIterator;
120
121    XASSERT(itsDynamicArray);
122    // rely on Init to sanity check array bounds
123
124    if (obj && !obj->init(itsDynamicArray, itsForward)) {
125	obj->release();
126	obj = nil;
127    }
128    return obj;
129
130} // CArrayIterator::CArrayIterator
131
132
133
134//--------------------------------------------------------------------------------
135//      CArrayIterator::CArrayIterator(4)
136//--------------------------------------------------------------------------------
137CArrayIterator *
138CArrayIterator::cArrayIterator(CDynamicArray* itsDynamicArray, ArrayIndex itsLowBound,
139    ArrayIndex itsHighBound, Boolean itsForward)
140{
141    CArrayIterator *obj = new CArrayIterator;
142
143    XASSERT(itsDynamicArray);
144    // rely on Init to sanity check array bounds
145
146    if (obj && !obj->init(itsDynamicArray, itsLowBound, itsHighBound, itsForward)) {
147	obj->release();
148	obj = nil;
149    }
150    return obj;
151
152} // CArrayIterator::CArrayIterator
153
154
155
156
157//--------------------------------------------------------------------------------
158//      CArrayIterator::free
159//--------------------------------------------------------------------------------
160void
161CArrayIterator::free()
162{
163    if (fDynamicArray) {
164	fDynamicArray->fIterator = RemoveFromList();
165	fDynamicArray = nil;
166    }
167
168    super::free();
169
170} // CArrayIterator::free
171
172
173//--------------------------------------------------------------------------------
174//      CArrayIterator::init(void)
175//--------------------------------------------------------------------------------
176bool
177CArrayIterator::init()
178{
179    if (!super::init()) return false;
180
181    fNextLink = this;
182    fPreviousLink = this;
183    fHighBound = kEmptyIndex;
184    fLowBound = kEmptyIndex;
185    fCurrentIndex = kEmptyIndex;
186    fIterateForward = kIterateForward;
187    fDynamicArray = nil;
188
189    return true;
190
191} // CArrayIterator::init
192
193//--------------------------------------------------------------------------------
194//      CArrayIterator::init(1)
195//--------------------------------------------------------------------------------
196Boolean
197CArrayIterator::init(CDynamicArray* itsDynamicArray)
198{
199    return init(itsDynamicArray, 0, itsDynamicArray->fSize - 1, kIterateForward);
200}
201
202//--------------------------------------------------------------------------------
203//      CArrayIterator::init(2)
204//--------------------------------------------------------------------------------
205Boolean
206CArrayIterator::init(CDynamicArray* itsDynamicArray, Boolean itsForward)
207{
208    return init(itsDynamicArray, 0, itsDynamicArray->fSize - 1, itsForward);
209}
210
211//--------------------------------------------------------------------------------
212//      CArrayIterator::init(4)
213//--------------------------------------------------------------------------------
214Boolean
215CArrayIterator::init(CDynamicArray* itsDynamicArray, ArrayIndex itsLowBound,
216    ArrayIndex itsHighBound, Boolean itsForward)
217{
218
219    if (!super::init()) return false;
220
221    require(itsDynamicArray, Fail);
222
223    fNextLink = this;
224    fPreviousLink = this;
225    fDynamicArray = itsDynamicArray;
226
227    // link me in to the list of iterations in progress
228    fDynamicArray->fIterator = AppendToList(fDynamicArray->fIterator);
229
230    // sanity check the bounds
231    InitBounds(itsLowBound, itsHighBound, itsForward);
232
233    return true;
234
235Fail:
236    return false;
237
238} // CArrayIterator::init
239
240
241//--------------------------------------------------------------------------------
242//      CArrayIterator::InitBounds
243//--------------------------------------------------------------------------------
244void CArrayIterator::InitBounds(ArrayIndex itsLowBound, ArrayIndex itsHighBound,
245    Boolean itsForward)
246{
247    fHighBound = (fDynamicArray->fSize > 0) ? MinMax(0, itsHighBound, fDynamicArray->fSize - 1) : kEmptyIndex;
248    fLowBound = (fHighBound > kEmptyIndex) ? MinMax(0, itsLowBound, fHighBound) : kEmptyIndex;
249
250    fIterateForward = itsForward;
251
252    Reset();
253
254} // CArrayIterator::Init
255
256
257//--------------------------------------------------------------------------------
258//      CArrayIterator::ResetBounds
259//--------------------------------------------------------------------------------
260void CArrayIterator::ResetBounds(Boolean goForward)
261{
262    fHighBound = (fDynamicArray->fSize > 0) ? fDynamicArray->fSize - 1 : kEmptyIndex;
263    fLowBound = (fHighBound > kEmptyIndex) ? 0 : kEmptyIndex;
264
265    fIterateForward = goForward;
266
267    Reset();
268
269} // CArrayIterator::Init
270
271
272//--------------------------------------------------------------------------------
273//      CArrayIterator::More
274//--------------------------------------------------------------------------------
275Boolean CArrayIterator::More()
276{
277    return (fDynamicArray != nil) ? (fCurrentIndex != kEmptyIndex) : false;
278
279} // CArrayIterator::More
280
281
282//--------------------------------------------------------------------------------
283//      CArrayIterator::Reset
284//--------------------------------------------------------------------------------
285void CArrayIterator::Reset()
286{
287    fCurrentIndex = (fIterateForward) ? fLowBound : fHighBound;
288
289} // CArrayIterator::Reset
290
291
292//--------------------------------------------------------------------------------
293//      CArrayIterator::DeleteArray
294//--------------------------------------------------------------------------------
295void CArrayIterator::DeleteArray()
296{
297    // inform everyone else in the list that the array is gone
298    if (fNextLink != fDynamicArray->fIterator)
299	fNextLink->DeleteArray();
300
301    // we no longer have an array
302    fDynamicArray = nil;
303
304} // CArrayIterator::~CArrayIterator
305
306
307//--------------------------------------------------------------------------------
308//      CArrayIterator::Advance
309//--------------------------------------------------------------------------------
310void CArrayIterator::Advance()
311{
312    if (fIterateForward)
313	{
314	if (fCurrentIndex < fHighBound)
315	    ++fCurrentIndex;
316	else
317	    fCurrentIndex = kEmptyIndex;
318	}
319    else
320	{
321	if (fCurrentIndex > fLowBound)
322	    --fCurrentIndex;
323	else
324	    fCurrentIndex = kEmptyIndex;
325	}
326
327} // CArrayIterator::Advance
328
329
330//--------------------------------------------------------------------------------
331//      CArrayIterator::RemoveElementsAt
332//--------------------------------------------------------------------------------
333void CArrayIterator::RemoveElementsAt(ArrayIndex theIndex, ArrayIndex theCount)
334{
335    // tuck the endpoints of the iteration in to match
336    if (theIndex < fLowBound)
337	fLowBound -= theCount;
338
339    if (theIndex <= fHighBound)
340	fHighBound -= theCount;
341
342    if (fIterateForward)
343	{
344	// If the removed element was !in the range yet to be iterated
345	// then bend the fCurrentIndex to account for it.
346	if (theIndex <= fCurrentIndex)
347	    fCurrentIndex -= theCount;
348	}
349    else
350	{
351	// Iterating backwards
352	// If the removed element was IN the range yet to be iterated
353	// then bend the fCurrentIndex to account for it.
354	if (theIndex < fCurrentIndex)
355	    fCurrentIndex -= theCount;
356	}
357
358    // hand off control to the next link until you hit the last
359    // link in the circular chain
360    if (fDynamicArray && fNextLink != fDynamicArray->fIterator)
361	fNextLink->RemoveElementsAt(theIndex, theCount);
362
363} // CArrayIterator::RemoveElementsAt
364
365
366//--------------------------------------------------------------------------------
367//      CArrayIterator::InsertElementsBefore
368//--------------------------------------------------------------------------------
369void CArrayIterator::InsertElementsBefore(ArrayIndex theIndex, ArrayIndex theCount)
370{
371    // bump the endpoints of this iteration out to match
372    if (theIndex <= fLowBound)
373	fLowBound += theCount;
374
375    if (theIndex <= fHighBound)
376	fHighBound += theCount;
377
378    if (fIterateForward)
379	{
380	// If the inserted element was !in the range yet to be
381	// iterated then bend the fCurrentIndex to account for it.
382	if (theIndex <= fCurrentIndex)
383	    fCurrentIndex += theCount;
384	}
385    else
386	{
387	// Iterating backward
388	// If the inserted element was IN the range yet to be
389	// iterated then bend the fCurrentIndex to account for it.
390	if (theIndex < fCurrentIndex)
391	    fCurrentIndex += theCount;
392	}
393
394    // hand off control to the next link until you hit the last
395    // link in the circular chain
396    if (fDynamicArray && fNextLink != fDynamicArray->fIterator)
397	fNextLink->InsertElementsBefore(theIndex, theCount);
398
399} // CArrayIterator::InsertElementsBefore
400
401
402//--------------------------------------------------------------------------------
403//      CArrayIterator::CurrentIndex
404//--------------------------------------------------------------------------------
405ArrayIndex CArrayIterator::CurrentIndex()
406{
407    return (fDynamicArray != nil) ? fCurrentIndex : kEmptyIndex;
408
409} // CArrayIterator::CurrentIndex
410
411
412//--------------------------------------------------------------------------------
413//      CArrayIterator::FirstIndex
414//--------------------------------------------------------------------------------
415ArrayIndex CArrayIterator::FirstIndex()
416{
417    Reset();
418
419    return More() ? fCurrentIndex : kEmptyIndex;
420
421} // CArrayIterator::FirstIndex
422
423
424//--------------------------------------------------------------------------------
425//      CArrayIterator::NextIndex
426//--------------------------------------------------------------------------------
427ArrayIndex CArrayIterator::NextIndex()
428{
429    Advance();
430
431    return More() ? fCurrentIndex : kEmptyIndex;
432
433} // CArrayIterator::NextIndex
434
435
436