Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sot/source/sdstor/stgavl.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <osl/diagnose.h>
21
#include "stgavl.hxx"
22
#include <assert.h>
23
24
StgAvlNode::StgAvlNode()
25
3.66M
{
26
3.66M
    m_pLeft = m_pRight = nullptr;
27
3.66M
    m_nBalance = m_nId = 0;
28
3.66M
}
29
30
StgAvlNode::~StgAvlNode()
31
3.66M
{
32
3.66M
    delete m_pLeft;
33
3.66M
    delete m_pRight;
34
3.66M
}
35
36
StgAvlNode* StgAvlNode::Find( StgAvlNode const * pFind )
37
1.88M
{
38
1.88M
    if ( pFind )
39
1.88M
    {
40
1.88M
        StgAvlNode* p = this;
41
6.08M
        while( p )
42
5.44M
        {
43
5.44M
            sal_Int32 nRes = p->Compare( pFind );
44
5.44M
            if( !nRes )
45
1.24M
                return p;
46
4.20M
            else p = ( nRes < 0 ) ? p->m_pLeft : p->m_pRight;
47
5.44M
        }
48
1.88M
    }
49
639k
    return nullptr;
50
1.88M
}
51
52
// find point to add node to AVL tree and returns
53
// +/0/- for >/=/< previous
54
55
sal_Int32 StgAvlNode::Locate
56
    ( StgAvlNode const * pFind,
57
      StgAvlNode** pPivot, StgAvlNode **pParent, StgAvlNode** pPrev )
58
1.22M
{
59
1.22M
    sal_Int32 nRes = 0;
60
1.22M
    StgAvlNode* pCur = this;
61
62
1.22M
    assert(pPivot && pParent && pPrev && "The pointers may not be NULL!");
63
1.22M
    *pParent = *pPrev = nullptr;
64
1.22M
    *pPivot = this;
65
66
    // search tree for insertion point
67
1.22M
    if ( pFind )
68
1.22M
    {
69
5.00M
        while( pCur != nullptr )
70
3.84M
        {
71
            // check for pPivot
72
3.84M
            if( pCur->m_nBalance != 0 )
73
2.85M
            {
74
2.85M
                *pPivot = pCur;
75
2.85M
                *pParent = *pPrev;
76
2.85M
            }
77
            // save pPrev location and see what direction to go
78
3.84M
            *pPrev = pCur;
79
3.84M
            nRes = pCur->Compare( pFind );
80
3.84M
            if( nRes == 0 )
81
57.2k
                break;
82
3.78M
            else pCur = ( nRes < 0 ) ? pCur->m_pLeft : pCur->m_pRight;
83
3.84M
        }
84
1.22M
    }
85
86
1.22M
    return nRes;
87
1.22M
}
88
89
// adjust balance factors in AVL tree from pivot down.
90
// Returns delta balance.
91
92
short StgAvlNode::Adjust( StgAvlNode** pHeavy, StgAvlNode const * pNew )
93
1.16M
{
94
1.16M
    StgAvlNode* pCur = this;
95
1.16M
    short nDelta;
96
    // no traversing
97
1.16M
    if( pCur == pNew || !pNew )
98
0
        return m_nBalance;
99
100
1.16M
    assert(pHeavy && pNew && "The pointers is not allowed to be NULL!");
101
102
1.16M
    sal_Int32 nRes = Compare( pNew );
103
1.16M
    if( nRes > 0 )
104
882k
    {
105
882k
        *pHeavy = pCur = m_pRight;
106
882k
        nDelta = -1;
107
882k
    }
108
284k
    else
109
284k
    {
110
284k
        *pHeavy = pCur = m_pLeft;
111
284k
        nDelta = 1;
112
284k
    }
113
1.16M
    m_nBalance = 0;
114
1.89M
    while( pCur != pNew )
115
729k
    {
116
729k
        nRes = pCur->Compare( pNew );
117
729k
        if( nRes > 0 )
118
544k
        {
119
            // height of right increases by 1
120
544k
            pCur->m_nBalance = -1;
121
544k
            pCur = pCur->m_pRight;
122
544k
        }
123
184k
        else
124
184k
        {
125
            // height of left increases by 1
126
184k
            pCur->m_nBalance = 1;
127
184k
            pCur = pCur->m_pLeft;
128
184k
        }
129
729k
    }
130
1.16M
    m_nBalance = m_nBalance + nDelta;
131
1.16M
    return nDelta;
132
1.16M
}
133
134
// perform LL rotation and return new root
135
136
StgAvlNode* StgAvlNode::RotLL()
137
0
{
138
0
    assert(m_pLeft && "The pointer is not allowed to be NULL!");
139
0
    StgAvlNode *pHeavy = m_pLeft;
140
0
    m_pLeft = pHeavy->m_pRight;
141
0
    pHeavy->m_pRight = this;
142
0
    pHeavy->m_nBalance = m_nBalance = 0;
143
0
    return pHeavy;
144
0
}
145
146
// perform LR rotation and return new root
147
148
StgAvlNode* StgAvlNode::RotLR()
149
0
{
150
0
    assert(m_pLeft && m_pLeft->m_pRight && "The pointer is not allowed to be NULL!");
151
0
    StgAvlNode* pHeavy = m_pLeft;
152
0
    StgAvlNode* pNewRoot = pHeavy->m_pRight;
153
154
0
    pHeavy->m_pRight = pNewRoot->m_pLeft;
155
0
    m_pLeft = pNewRoot->m_pRight;
156
0
    pNewRoot->m_pLeft = pHeavy;
157
0
    pNewRoot->m_pRight = this;
158
159
0
    switch( pNewRoot->m_nBalance )
160
0
    {
161
0
        case 1:     // LR( b )
162
0
            m_nBalance = -1;
163
0
            pHeavy->m_nBalance = 0;
164
0
            break;
165
0
        case -1:    // LR( c )
166
0
            pHeavy->m_nBalance = 1;
167
0
            m_nBalance = 0;
168
0
            break;
169
0
        case 0:     // LR( a )
170
0
            m_nBalance = 0;
171
0
            pHeavy->m_nBalance = 0;
172
0
            break;
173
0
    }
174
0
    pNewRoot->m_nBalance = 0;
175
0
    return pNewRoot;
176
0
}
177
178
// perform RR rotation and return new root
179
StgAvlNode* StgAvlNode::RotRR()
180
0
{
181
0
    assert(m_pRight && "The pointer is not allowed to be NULL!" );
182
0
    StgAvlNode* pHeavy = m_pRight;
183
0
    m_pRight = pHeavy->m_pLeft;
184
0
    pHeavy->m_pLeft = this;
185
0
    m_nBalance = pHeavy->m_nBalance = 0;
186
0
    return pHeavy;
187
0
}
188
189
// perform the RL rotation and return the new root
190
StgAvlNode* StgAvlNode::RotRL()
191
0
{
192
0
    assert(m_pRight && m_pRight->m_pLeft && "The pointer is not allowed to be NULL!");
193
0
    StgAvlNode* pHeavy = m_pRight;
194
0
    StgAvlNode* pNewRoot = pHeavy->m_pLeft;
195
0
    pHeavy->m_pLeft = pNewRoot->m_pRight;
196
0
    m_pRight = pNewRoot->m_pLeft;
197
0
    pNewRoot->m_pRight = pHeavy;
198
0
    pNewRoot->m_pLeft = this;
199
0
    switch( pNewRoot->m_nBalance )
200
0
    {
201
0
        case -1:    // RL( b )
202
0
            m_nBalance = 1;
203
0
            pHeavy->m_nBalance = 0;
204
0
            break;
205
0
        case 1:     // RL( c )
206
0
            pHeavy->m_nBalance = -1;
207
0
            m_nBalance = 0;
208
0
            break;
209
0
        case 0:     // RL( a )
210
0
            m_nBalance = 0;
211
0
            pHeavy->m_nBalance = 0;
212
0
            break;
213
0
    }
214
0
    pNewRoot->m_nBalance = 0;
215
0
    return pNewRoot;
216
0
}
217
218
// Remove a tree element. Return the removed element or NULL.
219
220
StgAvlNode* StgAvlNode::Rem( StgAvlNode** p, StgAvlNode* pDel, bool bPtrs )
221
4.50k
{
222
4.50k
    if( p && *p && pDel )
223
4.50k
    {
224
4.50k
        StgAvlNode* pCur = *p;
225
4.50k
        sal_Int32 nRes = bPtrs ? sal_Int32( pCur == pDel ) : pCur->Compare( pDel );
226
4.50k
        if( !nRes )
227
3.46k
        {
228
            // Element found: remove
229
3.46k
            if( !pCur->m_pRight )
230
2.25k
            {
231
2.25k
                *p = pCur->m_pLeft; pCur->m_pLeft = nullptr;
232
2.25k
            }
233
1.21k
            else if( !pCur->m_pLeft )
234
300
            {
235
300
                *p = pCur->m_pRight; pCur->m_pRight = nullptr;
236
300
            }
237
916
            else
238
916
            {
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
916
                StgAvlNode* last = pCur;
244
916
                StgAvlNode* l;
245
916
                for( l = pCur->m_pLeft;
246
3.75k
                     l->m_pRight; last = l, l = l->m_pRight ) {}
247
                // remove the element from chain
248
916
                if( l == last->m_pRight )
249
826
                    last->m_pRight = l->m_pLeft;
250
90
                else
251
90
                    last->m_pLeft = l->m_pLeft;
252
                // perform the replacement
253
916
                l->m_pLeft = pCur->m_pLeft;
254
916
                l->m_pRight = pCur->m_pRight;
255
916
                *p = l;
256
                // delete the element
257
916
                pCur->m_pLeft = pCur->m_pRight = nullptr;
258
916
            }
259
3.46k
            return pCur;
260
3.46k
        }
261
1.03k
        else
262
1.03k
        {
263
1.03k
            if( nRes < 0 )
264
12
                return Rem( &pCur->m_pLeft, pDel, bPtrs );
265
1.02k
            else
266
1.02k
                return Rem( &pCur->m_pRight, pDel, bPtrs );
267
1.03k
        }
268
4.50k
    }
269
0
    return nullptr;
270
4.50k
}
271
272
// Enumerate the tree for later iteration
273
274
void StgAvlNode::StgEnum( short& n )
275
5.06M
{
276
5.06M
    if( m_pLeft )
277
776k
        m_pLeft->StgEnum( n );
278
5.06M
    m_nId = n++;
279
5.06M
    if( m_pRight )
280
3.17M
        m_pRight->StgEnum( n );
281
5.06M
}
282
283
// Add node to AVL tree.
284
// Return false if the element already exists.
285
286
bool StgAvlNode::Insert( StgAvlNode** pRoot, StgAvlNode* pIns )
287
1.55M
{
288
1.55M
    StgAvlNode* pPivot, *pHeavy, *pParent, *pPrev;
289
1.55M
    if ( !pRoot )
290
0
        return false;
291
292
    // special case - empty tree
293
1.55M
    if( *pRoot == nullptr )
294
333k
    {
295
333k
        *pRoot = pIns;
296
333k
        return true;
297
333k
    }
298
    // find insertion point and return if already present
299
1.22M
    sal_Int32 nRes = (*pRoot)->Locate( pIns, &pPivot, &pParent, &pPrev );
300
1.22M
    if( !nRes )
301
57.2k
        return false;
302
303
1.22M
    assert(pPivot && pPrev && "The pointers may not be NULL!");
304
305
    // add new node
306
1.16M
    if( nRes < 0 )
307
323k
        pPrev->m_pLeft = pIns;
308
843k
    else
309
843k
        pPrev->m_pRight = pIns;
310
    // rebalance tree
311
1.16M
    short nDelta = pPivot->Adjust( &pHeavy, pIns );
312
1.16M
    if( pPivot->m_nBalance >= 2 || pPivot->m_nBalance <= -2 )
313
0
    {
314
0
        StgAvlNode* pNewRoot;
315
0
        pHeavy = ( nDelta < 0 ) ? pPivot->m_pRight : pPivot->m_pLeft;
316
        // left imbalance
317
0
        if( nDelta > 0 )
318
0
            if( pHeavy->m_nBalance == 1 )
319
0
                pNewRoot = pPivot->RotLL();
320
0
            else
321
0
                pNewRoot = pPivot->RotLR();
322
        // right imbalance
323
0
        else if( pHeavy->m_nBalance == -1 )
324
0
            pNewRoot = pPivot->RotRR();
325
0
        else
326
0
            pNewRoot = pPivot->RotRL();
327
        // relink balanced subtree
328
0
        if( pParent == nullptr )
329
0
            *pRoot = pNewRoot;
330
0
        else if( pPivot == pParent->m_pLeft )
331
0
            pParent->m_pLeft = pNewRoot;
332
0
        else if( pPivot == pParent->m_pRight )
333
0
            pParent->m_pRight = pNewRoot;
334
0
    }
335
1.16M
    return true;
336
1.22M
}
337
338
// Remove node from tree. Returns true is found and removed.
339
// Actually delete if bDel
340
341
bool StgAvlNode::Remove( StgAvlNode** pRoot, StgAvlNode* pDel, bool bDel )
342
3.46k
{
343
3.46k
    if ( !pRoot )
344
0
        return false;
345
346
    // special case - empty tree
347
3.46k
    if( *pRoot == nullptr )
348
0
        return false;
349
    // delete the element
350
3.46k
    pDel = Rem( pRoot, pDel, false );
351
3.46k
    if( pDel )
352
3.46k
    {
353
3.46k
        if( bDel )
354
3.46k
            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 )
359
        {
360
            StgAvlNode* p = Rem( pRoot, *pRoot, false );
361
            Insert( &pNew, p );
362
        }
363
        *pRoot = pNew;*/
364
3.46k
        return true;
365
3.46k
    }
366
0
    else
367
0
        return false;
368
3.46k
}
369
370
// Move node to a different tree. Returns true is found and moved. This routine
371
// may be called when the key has changed.
372
373
374
////////////////////////// class AvlIterator
375
376
// The iterator walks through a tree one entry by one.
377
378
StgAvlIterator::StgAvlIterator( StgAvlNode* p )
379
1.49M
{
380
1.49M
    m_pRoot = p;
381
1.49M
    m_nCur = 0;
382
1.49M
    if( p )
383
1.11M
    {
384
1.11M
        short nCount = 0; // tree size
385
1.11M
        p->StgEnum( nCount );
386
1.11M
    }
387
1.49M
}
388
389
StgAvlNode* StgAvlIterator::Find( short n )
390
6.55M
{
391
6.55M
    StgAvlNode* p = m_pRoot;
392
21.9M
    while( p )
393
20.4M
    {
394
20.4M
        if( n == p->m_nId )
395
5.06M
            break;
396
15.3M
        else p = ( n < p->m_nId ) ? p->m_pLeft : p->m_pRight;
397
20.4M
    }
398
6.55M
    return p;
399
6.55M
}
400
401
StgAvlNode* StgAvlIterator::First()
402
1.49M
{
403
1.49M
    m_nCur = -1;
404
1.49M
    return Next();
405
1.49M
}
406
407
StgAvlNode* StgAvlIterator::Next()
408
6.55M
{
409
6.55M
    return Find( ++m_nCur );
410
6.55M
}
411
412
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */