Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svl/source/notify/SfxBroadcaster.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 <svl/SfxBroadcaster.hxx>
21
22
#include <svl/hint.hxx>
23
#include <svl/lstner.hxx>
24
#include <tools/debug.hxx>
25
26
#include <algorithm>
27
#include <cassert>
28
#include <vector>
29
30
// Note: The loops in this file cannot be range-based
31
// because vectors can change size during the loops.
32
33
// broadcast immediately
34
35
void SfxBroadcaster::Broadcast(const SfxHint& rHint)
36
41.8M
{
37
    // notify all registered listeners exactly once
38
41.8M
    size_t nSize = m_Listeners.size();
39
143M
    for (size_t i = 0; i < nSize; ++i)
40
101M
    {
41
101M
        SfxListener* const pListener = m_Listeners[i];
42
101M
        if (pListener)
43
53.3M
            pListener->Notify(*this, rHint);
44
101M
    }
45
41.8M
}
46
47
// unregister all listeners
48
49
SfxBroadcaster::~SfxBroadcaster() COVERITY_NOEXCEPT_FALSE
50
26.3M
{
51
26.3M
    Broadcast(SfxHint(SfxHintId::Dying));
52
53
    // remove all still registered listeners
54
31.1M
    for (size_t i = 0; i < m_Listeners.size(); ++i)
55
4.78M
    {
56
4.78M
        SfxListener* const pListener = m_Listeners[i];
57
4.78M
        if (pListener)
58
467k
            pListener->RemoveBroadcaster_Impl(*this);
59
4.78M
    }
60
26.3M
}
61
62
// copy ctor of class SfxBroadcaster
63
64
SfxBroadcaster::SfxBroadcaster(const SfxBroadcaster& rOther)
65
0
{
66
0
    for (size_t i = 0; i < rOther.m_Listeners.size(); ++i)
67
0
    {
68
0
        SfxListener* const pListener = rOther.m_Listeners[i];
69
0
        if (pListener)
70
0
            pListener->StartListening(*this);
71
0
    }
72
0
}
73
74
// add a new SfxListener to the list
75
76
void SfxBroadcaster::AddListener(SfxListener& rListener)
77
7.89M
{
78
7.89M
    DBG_TESTSOLARMUTEX();
79
7.89M
    if (m_RemovedPositions.empty())
80
4.79M
    {
81
4.79M
        m_Listeners.push_back(&rListener);
82
4.79M
    }
83
3.10M
    else
84
3.10M
    {
85
3.10M
        size_t targetPosition = m_RemovedPositions.back();
86
3.10M
        m_RemovedPositions.pop_back();
87
3.10M
        assert(m_Listeners[targetPosition] == nullptr);
88
3.10M
        m_Listeners[targetPosition] = &rListener;
89
3.10M
    }
90
7.89M
}
91
92
// forward a notification to all registered listeners
93
94
void SfxBroadcaster::Forward(SfxBroadcaster& rBC, const SfxHint& rHint)
95
36.1M
{
96
66.5M
    for (size_t i = 0; i < m_Listeners.size(); ++i)
97
30.4M
    {
98
30.4M
        SfxListener* const pListener = m_Listeners[i];
99
30.4M
        if (pListener)
100
27.1M
            pListener->Notify(rBC, rHint);
101
30.4M
    }
102
36.1M
}
103
104
// remove one SfxListener from the list
105
106
void SfxBroadcaster::RemoveListener(SfxListener& rListener)
107
7.42M
{
108
7.42M
    DBG_TESTSOLARMUTEX();
109
110
    // First, check the slots either side of the last removed slot, makes a significant
111
    // difference when the list is large.
112
7.42M
    int positionOfRemovedElement = -1;
113
7.42M
    if (!m_RemovedPositions.empty())
114
4.05M
    {
115
4.05M
        auto i = m_RemovedPositions.back();
116
4.05M
        if (i < m_Listeners.size() - 2 && m_Listeners[i + 1] == &rListener)
117
726k
        {
118
726k
            positionOfRemovedElement = i + 1;
119
726k
        }
120
3.32M
        else if (i > 0 && m_Listeners[i - 1] == &rListener)
121
1.68M
        {
122
1.68M
            positionOfRemovedElement = i - 1;
123
1.68M
        }
124
4.05M
    }
125
    // then scan the whole list if we didn't find it
126
7.42M
    if (positionOfRemovedElement == -1)
127
5.01M
    {
128
5.01M
        auto aIter = std::find(m_Listeners.begin(), m_Listeners.end(), &rListener);
129
5.01M
        positionOfRemovedElement = std::distance(m_Listeners.begin(), aIter);
130
5.01M
    }
131
    // DO NOT erase the listener, set the pointer to 0
132
    // because the current continuation may contain this->Broadcast
133
7.42M
    m_Listeners[positionOfRemovedElement] = nullptr;
134
7.42M
    m_RemovedPositions.push_back(positionOfRemovedElement);
135
7.42M
}
136
137
void SfxBroadcaster::ForAllListeners(const std::function<bool(SfxListener*)>& f) const
138
672k
{
139
3.99M
    for (size_t i = 0; i < m_Listeners.size(); ++i)
140
3.34M
    {
141
3.34M
        SfxListener* const pListener = m_Listeners[i];
142
3.34M
        if (pListener)
143
3.02M
            if (f(pListener))
144
14.5k
                break;
145
3.34M
    }
146
672k
}
147
148
883k
bool SfxBroadcaster::HasListeners() const { return GetListenerCount() != 0; }
149
150
size_t SfxBroadcaster::GetListenerCount() const
151
883k
{
152
883k
    return m_Listeners.size() - m_RemovedPositions.size();
153
883k
}
154
155
0
bool SfxBroadcaster::IsSfxStyleSheet() const { return false; }
156
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */