tdf#143148 Use #pragma once instead of include guards
[LibreOffice.git] / sot / source / sdstor / stgavl.cxx
blobac0c5f468024aac7ed80eadce6c8bffbf4104ceb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include "stgavl.hxx"
22 #include <assert.h>
24 StgAvlNode::StgAvlNode()
26 m_pLeft = m_pRight = nullptr;
27 m_nBalance = m_nId = 0;
30 StgAvlNode::~StgAvlNode()
32 delete m_pLeft;
33 delete m_pRight;
36 StgAvlNode* StgAvlNode::Find( StgAvlNode const * pFind )
38 if ( pFind )
40 StgAvlNode* p = this;
41 while( p )
43 sal_Int32 nRes = p->Compare( pFind );
44 if( !nRes )
45 return p;
46 else p = ( nRes < 0 ) ? p->m_pLeft : p->m_pRight;
49 return nullptr;
52 // find point to add node to AVL tree and returns
53 // +/0/- for >/=/< previous
55 sal_Int32 StgAvlNode::Locate
56 ( StgAvlNode const * pFind,
57 StgAvlNode** pPivot, StgAvlNode **pParent, StgAvlNode** pPrev )
59 sal_Int32 nRes = 0;
60 StgAvlNode* pCur = this;
62 assert(pPivot && pParent && pPrev && "The pointers may not be NULL!");
63 *pParent = *pPrev = nullptr;
64 *pPivot = this;
66 // search tree for insertion point
67 if ( pFind )
69 while( pCur != nullptr )
71 // check for pPivot
72 if( pCur->m_nBalance != 0 )
74 *pPivot = pCur;
75 *pParent = *pPrev;
77 // save pPrev location and see what direction to go
78 *pPrev = pCur;
79 nRes = pCur->Compare( pFind );
80 if( nRes == 0 )
81 break;
82 else pCur = ( nRes < 0 ) ? pCur->m_pLeft : pCur->m_pRight;
86 return nRes;
89 // adjust balance factors in AVL tree from pivot down.
90 // Returns delta balance.
92 short StgAvlNode::Adjust( StgAvlNode** pHeavy, StgAvlNode const * pNew )
94 StgAvlNode* pCur = this;
95 short nDelta;
96 // no traversing
97 if( pCur == pNew || !pNew )
98 return m_nBalance;
100 assert(pHeavy && pNew && "The pointers is not allowed to be NULL!");
102 sal_Int32 nRes = Compare( pNew );
103 if( nRes > 0 )
105 *pHeavy = pCur = m_pRight;
106 nDelta = -1;
108 else
110 *pHeavy = pCur = m_pLeft;
111 nDelta = 1;
113 m_nBalance = 0;
114 while( pCur != pNew )
116 nRes = pCur->Compare( pNew );
117 if( nRes > 0 )
119 // height of right increases by 1
120 pCur->m_nBalance = -1;
121 pCur = pCur->m_pRight;
123 else
125 // height of left increases by 1
126 pCur->m_nBalance = 1;
127 pCur = pCur->m_pLeft;
130 m_nBalance = m_nBalance + nDelta;
131 return nDelta;
134 // perform LL rotation and return new root
136 StgAvlNode* StgAvlNode::RotLL()
138 assert(m_pLeft && "The pointer is not allowed to be NULL!");
139 StgAvlNode *pHeavy = m_pLeft;
140 m_pLeft = pHeavy->m_pRight;
141 pHeavy->m_pRight = this;
142 pHeavy->m_nBalance = m_nBalance = 0;
143 return pHeavy;
146 // perform LR rotation and return new root
148 StgAvlNode* StgAvlNode::RotLR()
150 assert(m_pLeft && m_pLeft->m_pRight && "The pointer is not allowed to be NULL!");
151 StgAvlNode* pHeavy = m_pLeft;
152 StgAvlNode* pNewRoot = pHeavy->m_pRight;
154 pHeavy->m_pRight = pNewRoot->m_pLeft;
155 m_pLeft = pNewRoot->m_pRight;
156 pNewRoot->m_pLeft = pHeavy;
157 pNewRoot->m_pRight = this;
159 switch( pNewRoot->m_nBalance )
161 case 1: // LR( b )
162 m_nBalance = -1;
163 pHeavy->m_nBalance = 0;
164 break;
165 case -1: // LR( c )
166 pHeavy->m_nBalance = 1;
167 m_nBalance = 0;
168 break;
169 case 0: // LR( a )
170 m_nBalance = 0;
171 pHeavy->m_nBalance = 0;
172 break;
174 pNewRoot->m_nBalance = 0;
175 return pNewRoot;
178 // perform RR rotation and return new root
179 StgAvlNode* StgAvlNode::RotRR()
181 assert(m_pRight && "The pointer is not allowed to be NULL!" );
182 StgAvlNode* pHeavy = m_pRight;
183 m_pRight = pHeavy->m_pLeft;
184 pHeavy->m_pLeft = this;
185 m_nBalance = pHeavy->m_nBalance = 0;
186 return pHeavy;
189 // perform the RL rotation and return the new root
190 StgAvlNode* StgAvlNode::RotRL()
192 assert(m_pRight && m_pRight->m_pLeft && "The pointer is not allowed to be NULL!");
193 StgAvlNode* pHeavy = m_pRight;
194 StgAvlNode* pNewRoot = pHeavy->m_pLeft;
195 pHeavy->m_pLeft = pNewRoot->m_pRight;
196 m_pRight = pNewRoot->m_pLeft;
197 pNewRoot->m_pRight = pHeavy;
198 pNewRoot->m_pLeft = this;
199 switch( pNewRoot->m_nBalance )
201 case -1: // RL( b )
202 m_nBalance = 1;
203 pHeavy->m_nBalance = 0;
204 break;
205 case 1: // RL( c )
206 pHeavy->m_nBalance = -1;
207 m_nBalance = 0;
208 break;
209 case 0: // RL( a )
210 m_nBalance = 0;
211 pHeavy->m_nBalance = 0;
212 break;
214 pNewRoot->m_nBalance = 0;
215 return pNewRoot;
218 // Remove a tree element. Return the removed element or NULL.
220 StgAvlNode* StgAvlNode::Rem( StgAvlNode** p, StgAvlNode* pDel, bool bPtrs )
222 if( p && *p && pDel )
224 StgAvlNode* pCur = *p;
225 sal_Int32 nRes = bPtrs ? sal_Int32( pCur == pDel ) : pCur->Compare( pDel );
226 if( !nRes )
228 // Element found: remove
229 if( !pCur->m_pRight )
231 *p = pCur->m_pLeft; pCur->m_pLeft = nullptr;
233 else if( !pCur->m_pLeft )
235 *p = pCur->m_pRight; pCur->m_pRight = nullptr;
237 else
239 // The damn element has two leaves. Get the
240 // rightmost element of the left subtree (which
241 // is lexically before this element) and replace
242 // this element with the element found.
243 StgAvlNode* last = pCur;
244 StgAvlNode* l;
245 for( l = pCur->m_pLeft;
246 l->m_pRight; last = l, l = l->m_pRight ) {}
247 // remove the element from chain
248 if( l == last->m_pRight )
249 last->m_pRight = l->m_pLeft;
250 else
251 last->m_pLeft = l->m_pLeft;
252 // perform the replacement
253 l->m_pLeft = pCur->m_pLeft;
254 l->m_pRight = pCur->m_pRight;
255 *p = l;
256 // delete the element
257 pCur->m_pLeft = pCur->m_pRight = nullptr;
259 return pCur;
261 else
263 if( nRes < 0 )
264 return Rem( &pCur->m_pLeft, pDel, bPtrs );
265 else
266 return Rem( &pCur->m_pRight, pDel, bPtrs );
269 return nullptr;
272 // Enumerate the tree for later iteration
274 void StgAvlNode::StgEnum( short& n )
276 if( m_pLeft )
277 m_pLeft->StgEnum( n );
278 m_nId = n++;
279 if( m_pRight )
280 m_pRight->StgEnum( n );
283 // Add node to AVL tree.
284 // Return false if the element already exists.
286 bool StgAvlNode::Insert( StgAvlNode** pRoot, StgAvlNode* pIns )
288 StgAvlNode* pPivot, *pHeavy, *pParent, *pPrev;
289 if ( !pRoot )
290 return false;
292 // special case - empty tree
293 if( *pRoot == nullptr )
295 *pRoot = pIns;
296 return true;
298 // find insertion point and return if already present
299 sal_Int32 nRes = (*pRoot)->Locate( pIns, &pPivot, &pParent, &pPrev );
300 if( !nRes )
301 return false;
303 assert(pPivot && pPrev && "The pointers may not be NULL!");
305 // add new node
306 if( nRes < 0 )
307 pPrev->m_pLeft = pIns;
308 else
309 pPrev->m_pRight = pIns;
310 // rebalance tree
311 short nDelta = pPivot->Adjust( &pHeavy, pIns );
312 if( pPivot->m_nBalance >= 2 || pPivot->m_nBalance <= -2 )
314 StgAvlNode* pNewRoot;
315 pHeavy = ( nDelta < 0 ) ? pPivot->m_pRight : pPivot->m_pLeft;
316 // left imbalance
317 if( nDelta > 0 )
318 if( pHeavy->m_nBalance == 1 )
319 pNewRoot = pPivot->RotLL();
320 else
321 pNewRoot = pPivot->RotLR();
322 // right imbalance
323 else if( pHeavy->m_nBalance == -1 )
324 pNewRoot = pPivot->RotRR();
325 else
326 pNewRoot = pPivot->RotRL();
327 // relink balanced subtree
328 if( pParent == nullptr )
329 *pRoot = pNewRoot;
330 else if( pPivot == pParent->m_pLeft )
331 pParent->m_pLeft = pNewRoot;
332 else if( pPivot == pParent->m_pRight )
333 pParent->m_pRight = pNewRoot;
335 return true;
338 // Remove node from tree. Returns true is found and removed.
339 // Actually delete if bDel
341 bool StgAvlNode::Remove( StgAvlNode** pRoot, StgAvlNode* pDel, bool bDel )
343 if ( !pRoot )
344 return false;
346 // special case - empty tree
347 if( *pRoot == nullptr )
348 return false;
349 // delete the element
350 pDel = Rem( pRoot, pDel, false );
351 if( pDel )
353 if( bDel )
354 delete pDel;
355 // Rebalance the tree the hard way
356 // OS 22.09.95: On MD's request commented out due to crash
357 /* StgAvlNode* pNew = NULL;
358 while( *pRoot )
360 StgAvlNode* p = Rem( pRoot, *pRoot, false );
361 Insert( &pNew, p );
363 *pRoot = pNew;*/
364 return true;
366 else
367 return false;
370 // Move node to a different tree. Returns true is found and moved. This routine
371 // may be called when the key has changed.
374 ////////////////////////// class AvlIterator
376 // The iterator walks through a tree one entry by one.
378 StgAvlIterator::StgAvlIterator( StgAvlNode* p )
380 m_pRoot = p;
381 m_nCur = 0;
382 if( p )
384 short nCount = 0; // tree size
385 p->StgEnum( nCount );
389 StgAvlNode* StgAvlIterator::Find( short n )
391 StgAvlNode* p = m_pRoot;
392 while( p )
394 if( n == p->m_nId )
395 break;
396 else p = ( n < p->m_nId ) ? p->m_pLeft : p->m_pRight;
398 return p;
401 StgAvlNode* StgAvlIterator::First()
403 m_nCur = -1;
404 return Next();
407 StgAvlNode* StgAvlIterator::Next()
409 return Find( ++m_nCur );
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */