b311480e |
1 | // Copyright (c) 1998-1999 Matra Datavision |
973c2be1 |
2 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
b311480e |
3 | // |
973c2be1 |
4 | // This file is part of Open CASCADE Technology software library. |
b311480e |
5 | // |
d5f74e42 |
6 | // This library is free software; you can redistribute it and/or modify it under |
7 | // the terms of the GNU Lesser General Public License version 2.1 as published |
973c2be1 |
8 | // by the Free Software Foundation, with special exception defined in the file |
9 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
10 | // distribution for complete text of the license and disclaimer of any warranty. |
b311480e |
11 | // |
973c2be1 |
12 | // Alternatively, this file may be used under the terms of Open CASCADE |
13 | // commercial license or contractual agreement. |
b311480e |
14 | |
7fd59977 |
15 | #include <TCollection_BaseSequence.ixx> |
16 | #include <Standard_NoSuchObject.hxx> |
17 | #include <Standard_OutOfRange.hxx> |
18 | #include <Standard_DomainError.hxx> |
19 | #include <TCollection_SeqNode.hxx> |
20 | |
21 | typedef void (*DelNode) (TCollection_SeqNode*); |
22 | |
23 | TCollection_BaseSequence::TCollection_BaseSequence() : |
24 | FirstItem(NULL), |
25 | LastItem(NULL), |
26 | CurrentItem(NULL), |
27 | CurrentIndex(0), |
28 | Size(0) |
29 | { |
30 | } |
31 | |
32 | |
33 | |
34 | // ---------------------------------- |
35 | // Clear : Clear the Current Sequence |
36 | // ---------------------------------- |
37 | void TCollection_BaseSequence::Clear(const Standard_Address delnode) |
38 | { |
39 | Size = 0; |
40 | TCollection_SeqNode* p = (TCollection_SeqNode*) FirstItem; |
41 | TCollection_SeqNode* q; |
42 | while (p) { |
43 | q = p; |
44 | p = p->Next(); |
45 | ((DelNode)delnode) (q); |
46 | } |
47 | LastItem = FirstItem = CurrentItem = NULL; |
48 | CurrentIndex = 0; |
49 | } |
50 | |
51 | void TCollection_BaseSequence::PAppend(const Standard_Address newnode) |
52 | { |
53 | if (Size == 0) { |
54 | FirstItem = LastItem = CurrentItem = newnode; |
55 | CurrentIndex = Size = 1; |
56 | } |
57 | else { |
58 | ((TCollection_SeqNode*)LastItem)->Next() = (TCollection_SeqNode*)newnode; |
59 | LastItem = newnode; |
60 | Size++; |
61 | } |
62 | } |
63 | |
64 | // --------------------------------------------------- |
65 | // Append : Push a sequence at the end of the sequence |
66 | // --------------------------------------------------- |
67 | void TCollection_BaseSequence::PAppend(TCollection_BaseSequence& Other) |
68 | { |
69 | if (Size == 0) { |
70 | Size = Other.Size; |
71 | FirstItem = Other.FirstItem; |
72 | LastItem = Other.LastItem; |
73 | CurrentItem = FirstItem; |
74 | CurrentIndex = 1; |
75 | } |
76 | else { |
77 | Size += Other.Size; |
78 | ((TCollection_SeqNode*)LastItem)->Next() = (TCollection_SeqNode*)Other.FirstItem; |
79 | if (Other.FirstItem) { |
80 | ((TCollection_SeqNode*)Other.FirstItem)->Previous() = (TCollection_SeqNode*)LastItem; |
81 | LastItem = Other.LastItem; |
82 | } |
83 | } |
84 | Other.Nullify(); |
85 | } |
86 | |
87 | |
88 | |
89 | void TCollection_BaseSequence::PPrepend(const Standard_Address newnode) |
90 | { |
91 | if (Size == 0) { |
92 | FirstItem = LastItem = CurrentItem = newnode; |
93 | CurrentIndex = Size = 1; |
94 | } |
95 | else { |
96 | ((TCollection_SeqNode*)FirstItem)->Previous() = (TCollection_SeqNode*) newnode; |
97 | ((TCollection_SeqNode*)newnode)->Next() = (TCollection_SeqNode*)FirstItem; |
98 | FirstItem = newnode; |
99 | Size++; |
100 | CurrentIndex++; |
101 | } |
102 | } |
103 | |
104 | void TCollection_BaseSequence::PPrepend(TCollection_BaseSequence& Other) |
105 | { |
106 | if (Size == 0) { |
107 | Size = Other.Size; |
108 | FirstItem = Other.FirstItem; |
109 | LastItem = Other.LastItem; |
110 | CurrentIndex = 1; |
111 | CurrentItem = FirstItem; |
112 | } |
113 | else { |
114 | Size += Other.Size; |
115 | if (Other.LastItem) ((TCollection_SeqNode*)Other.LastItem)->Next() = (TCollection_SeqNode*)FirstItem; |
116 | ((TCollection_SeqNode*)FirstItem)->Previous() = (TCollection_SeqNode*)Other.LastItem; |
117 | FirstItem = Other.FirstItem; |
118 | CurrentIndex += Other.Size; |
119 | } |
120 | Other.Nullify(); |
121 | } |
122 | |
123 | // --------------------------------------------------------- |
124 | // Reverse : Reverse the order of a given sequence |
125 | // --------------------------------------------------------- |
126 | void TCollection_BaseSequence::Reverse() |
127 | { |
128 | TCollection_SeqNode* p = (TCollection_SeqNode*) FirstItem; |
129 | TCollection_SeqNode* tmp; |
130 | while (p) { |
131 | tmp = p->Next(); |
132 | p->Next() = p->Previous(); |
133 | p->Previous() = tmp; |
134 | p = tmp; |
135 | } |
136 | tmp = (TCollection_SeqNode*)FirstItem; |
137 | FirstItem = LastItem; |
138 | LastItem = tmp; |
139 | if (Size != 0) CurrentIndex = Size + 1 - CurrentIndex; |
140 | } |
141 | |
142 | |
143 | void TCollection_BaseSequence::PInsertAfter(const Standard_Integer Index, const Standard_Address N) |
144 | { |
145 | if (Index == 0) |
146 | PPrepend(N); |
147 | else { |
148 | TCollection_SeqNode* p = (TCollection_SeqNode*) Find(Index); |
149 | TCollection_SeqNode* newnode = (TCollection_SeqNode*) N; |
150 | newnode->Next() = p->Next(); |
151 | newnode->Previous() = p; |
152 | if (Index == Size) LastItem = newnode; |
153 | else p->Next()->Previous() = newnode; |
154 | p->Next() = newnode; |
155 | Size++; |
156 | if (Index < CurrentIndex) CurrentIndex++; |
157 | } |
158 | } |
159 | |
160 | // ------------------------------------------------------------------- |
161 | // InsertAfter : Insert a sequence after a given index in the sequence |
162 | // ------------------------------------------------------------------- |
163 | |
164 | void TCollection_BaseSequence::PInsertAfter(const Standard_Integer Index, TCollection_BaseSequence& Other) |
165 | { |
166 | if (Index < 0 || Index > Size) Standard_OutOfRange::Raise(); |
167 | if (Other.Size == 0) return; |
168 | if (Index == 0) |
169 | PPrepend( Other ); |
170 | else { |
171 | TCollection_SeqNode* p = (TCollection_SeqNode*) Find(Index); |
172 | ((TCollection_SeqNode*)Other.FirstItem)->Previous() = p; |
173 | ((TCollection_SeqNode*)Other.LastItem)->Next() = p->Next(); |
174 | if (Index == Size) LastItem = Other.LastItem; |
175 | else p->Next()->Previous() = (TCollection_SeqNode*)Other.LastItem; |
176 | p->Next() = (TCollection_SeqNode*)Other.FirstItem; |
177 | Size += Other.Size; |
178 | if (Index < CurrentIndex) CurrentIndex += Other.Size; |
179 | Other.Nullify(); |
180 | } |
181 | } |
182 | |
183 | // ---------------------------------------- |
184 | // Exchange : Exchange two elements in the sequence |
185 | // ---------------------------------------- |
186 | void TCollection_BaseSequence::Exchange(const Standard_Integer I, const Standard_Integer J) |
187 | { |
188 | Standard_OutOfRange_Raise_if ( I <= 0 || J <= 0 || I > Size || J > Size,"" ) ; |
189 | |
190 | // Assume I < J |
191 | if (I == J) return; |
192 | if (J < I) { |
193 | Exchange(J,I); |
194 | return; |
195 | } |
196 | |
197 | TCollection_SeqNode* pi = (TCollection_SeqNode*) Find(I); |
198 | TCollection_SeqNode* pj = (TCollection_SeqNode*) Find(J); |
199 | |
200 | // update the node before I |
201 | if (pi->Previous()) |
202 | pi->Previous()->Next() = pj; |
203 | else |
204 | FirstItem = pj; |
205 | |
206 | // update the node after J |
207 | if (pj->Next()) |
208 | pj->Next()->Previous() = pi; |
209 | else |
210 | LastItem = pi; |
211 | |
212 | if (pi->Next() == pj) { // I and J are consecutives, update them |
213 | pj->Previous() = pi->Previous(); |
214 | pi->Previous() = pj; |
215 | pi->Next() = pj->Next(); |
216 | pj->Next() = pi; |
217 | } |
218 | else { // I and J are not consecutive |
219 | pi->Next()->Previous() = pj; // update the node after I |
220 | pj->Previous()->Next() = pi; // update the node before J |
221 | TCollection_SeqNode* tmp = pi->Next(); // update nodes I and J |
222 | pi->Next() = pj->Next(); |
223 | pj->Next() = tmp; |
224 | tmp = pi->Previous(); |
225 | pi->Previous() = pj->Previous(); |
226 | pj->Previous() = tmp; |
227 | } |
228 | |
229 | if (CurrentIndex == I) CurrentItem = pj; |
230 | else if (CurrentIndex == J) CurrentItem = pi; |
231 | } |
232 | |
233 | void TCollection_BaseSequence::PSplit(const Standard_Integer Index, TCollection_BaseSequence& Sub) |
234 | { |
235 | Standard_OutOfRange_Raise_if( Index <= 0 || Index > Size,"" ); |
236 | Standard_DomainError_Raise_if(this == &Sub,"No Split on myself!!"); |
237 | |
238 | TCollection_SeqNode* p = (TCollection_SeqNode*) Find(Index); |
239 | |
240 | Sub.LastItem = LastItem; |
241 | Sub.Size = Size - Index + 1; |
242 | |
243 | LastItem = p->Previous(); |
244 | if (LastItem) { |
245 | ((TCollection_SeqNode*)LastItem)->Next() = NULL; |
246 | Size = Index - 1; |
247 | if (CurrentIndex >= Index) { |
248 | CurrentIndex = 1; |
249 | CurrentItem = (TCollection_SeqNode*) FirstItem; |
250 | } |
251 | } |
252 | else { |
253 | FirstItem = CurrentItem = NULL; |
254 | Size = CurrentIndex = 0; |
255 | } |
256 | |
257 | Sub.FirstItem = Sub.CurrentItem = p; |
258 | p->Previous() = NULL; |
259 | Sub.CurrentIndex = 1; |
260 | } |
261 | |
262 | void TCollection_BaseSequence::Remove(const Standard_Integer Index, const Standard_Address delnode) |
263 | { |
264 | Standard_OutOfRange_Raise_if(Index <= 0 || Index > Size,"" ); |
265 | |
266 | TCollection_SeqNode* p = (TCollection_SeqNode*) Find(Index); |
267 | if (p->Previous()) |
268 | p->Previous()->Next() = p->Next(); |
269 | else |
270 | FirstItem = p->Next(); |
271 | if (p->Next()) |
272 | p->Next()->Previous() = p->Previous(); |
273 | else |
274 | LastItem = p->Previous(); |
275 | |
276 | Size--; |
277 | if (CurrentIndex > Index) CurrentIndex--; |
278 | else if (CurrentIndex == Index) { |
279 | if (p->Next()) |
280 | CurrentItem = p->Next(); |
281 | else { |
282 | CurrentItem = (TCollection_SeqNode*) LastItem; |
283 | CurrentIndex = Size; |
284 | } |
285 | } |
286 | ((DelNode)delnode) (p); |
287 | } |
288 | |
289 | // --------------------- |
290 | // Remove a set of items |
291 | // --------------------- |
292 | void TCollection_BaseSequence::Remove(const Standard_Integer From, const Standard_Integer To, |
293 | const Standard_Address delnode) |
294 | { |
295 | Standard_OutOfRange_Raise_if (From <= 0 || From > Size || To <= 0 || To > Size || From > To,"" ); |
296 | |
297 | TCollection_SeqNode* pfrom = (TCollection_SeqNode*) Find(From); |
298 | TCollection_SeqNode* pto = (TCollection_SeqNode*) Find(To); |
299 | |
300 | if (pfrom->Previous()) |
301 | pfrom->Previous()->Next() = pto->Next(); |
302 | else |
303 | FirstItem = pto->Next(); |
304 | if (pto->Next()) |
305 | pto->Next()->Previous() = pfrom->Previous(); |
306 | else |
307 | LastItem = pfrom->Previous(); |
308 | |
309 | Size -= To - From + 1; |
310 | if (CurrentIndex > To) |
311 | CurrentIndex -= To - From + 1; |
312 | else if (CurrentIndex >= From) { |
313 | if (pto->Next()) { |
314 | CurrentItem = pto->Next(); |
315 | CurrentIndex = From; // AGV fix 24.05.01 |
316 | } else { |
317 | CurrentItem = (TCollection_SeqNode*) LastItem; |
318 | CurrentIndex = Size; |
319 | } |
320 | } |
321 | |
322 | Standard_Integer i; |
323 | for (i = From; i <= To; i++) { |
324 | pto = pfrom; |
325 | pfrom = pfrom->Next(); |
326 | ((DelNode)delnode) (pto); |
327 | } |
328 | } |
329 | |
330 | Standard_Address TCollection_BaseSequence::Find(const Standard_Integer Index) const |
331 | { |
332 | Standard_Integer i; |
333 | TCollection_SeqNode* p; |
334 | if (Index <= CurrentIndex) { |
335 | if (Index < CurrentIndex / 2) { |
336 | p = (TCollection_SeqNode*) FirstItem; |
337 | for (i = 1; i < Index; i++) p = p->Next(); |
338 | } |
339 | else { |
340 | p = (TCollection_SeqNode*) CurrentItem; |
341 | for (i = CurrentIndex; i > Index; i--) p = p->Previous(); |
342 | } |
343 | } |
344 | else { |
345 | if (Index < (CurrentIndex + Size) / 2) { |
346 | p = (TCollection_SeqNode*) CurrentItem; |
347 | for (i = CurrentIndex; i < Index; i++) p = p->Next(); |
348 | } |
349 | else { |
350 | p = (TCollection_SeqNode*) LastItem; |
351 | for (i = Size; i > Index; i--) p = p->Previous(); |
352 | } |
353 | } |
354 | return p; |
355 | } |
356 | |
357 | //======================================================================= |
358 | //function : Nullify |
359 | //purpose : |
360 | //======================================================================= |
361 | |
362 | void TCollection_BaseSequence::Nullify() |
363 | { |
364 | FirstItem = LastItem = CurrentItem = NULL; |
365 | CurrentIndex = Size = 0; |
366 | } |