Coverage Report

Created: 2026-10-14 09:33

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
45.1M
{
37
    // notify all registered listeners exactly once
38
45.1M
    size_t nSize = m_Listeners.size();
39
806M
    for (size_t i = 0; i < nSize; ++i)
40
761M
    {
41
761M
        SfxListener* const pListener = m_Listeners[i];
42
761M
        if (pListener)
43
578M
            pListener->Notify(*this, rHint);
44
761M
    }
45
45.1M
}
46
47
// unregister all listeners
48
49
SfxBroadcaster::~SfxBroadcaster() COVERITY_NOEXCEPT_FALSE
50
27.1M
{
51
27.1M
    Broadcast(SfxHint(SfxHintId::Dying));
52
53
    // remove all still registered listeners
54
32.7M
    for (size_t i = 0; i < m_Listeners.size(); ++i)
55
5.60M
    {
56
5.60M
        SfxListener* const pListener = m_Listeners[i];
57
5.60M
        if (pListener)
58
482k
            pListener->RemoveBroadcaster_Impl(*this);
59
5.60M
    }
60
27.1M
}
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
8.88M
{
78
8.88M
    DBG_TESTSOLARMUTEX();
79
8.88M
    if (m_RemovedPositions.empty())
80
5.60M
    {
81
5.60M
        m_Listeners.push_back(&rListener);
82
5.60M
    }
83
3.27M
    else
84
3.27M
    {
85
3.27M
        size_t targetPosition = m_RemovedPositions.back();
86
3.27M
        m_RemovedPositions.pop_back();
87
3.27M
        assert(m_Listeners[targetPosition] == nullptr);
88
3.27M
        m_Listeners[targetPosition] = &rListener;
89
3.27M
    }
90
8.88M
}
91
92
// forward a notification to all registered listeners
93
94
void SfxBroadcaster::Forward(SfxBroadcaster& rBC, const SfxHint& rHint)
95
37.6M
{
96
69.4M
    for (size_t i = 0; i < m_Listeners.size(); ++i)
97
31.8M
    {
98
31.8M
        SfxListener* const pListener = m_Listeners[i];
99
31.8M
        if (pListener)
100
28.2M
            pListener->Notify(rBC, rHint);
101
31.8M
    }
102
37.6M
}
103
104
// remove one SfxListener from the list
105
106
void SfxBroadcaster::RemoveListener(SfxListener& rListener)
107
8.40M
{
108
8.40M
    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
8.40M
    int positionOfRemovedElement = -1;
113
8.40M
    if (!m_RemovedPositions.empty())
114
4.25M
    {
115
4.25M
        auto i = m_RemovedPositions.back();
116
4.25M
        if (i < m_Listeners.size() - 2 && m_Listeners[i + 1] == &rListener)
117
729k
        {
118
729k
            positionOfRemovedElement = i + 1;
119
729k
        }
120
3.52M
        else if (i > 0 && m_Listeners[i - 1] == &rListener)
121
1.93M
        {
122
1.93M
            positionOfRemovedElement = i - 1;
123
1.93M
        }
124
4.25M
    }
125
    // then scan the whole list if we didn't find it
126
8.40M
    if (positionOfRemovedElement == -1)
127
5.73M
    {
128
5.73M
        auto aIter = std::find(m_Listeners.begin(), m_Listeners.end(), &rListener);
129
5.73M
        positionOfRemovedElement = std::distance(m_Listeners.begin(), aIter);
130
5.73M
    }
131
    // DO NOT erase the listener, set the pointer to 0
132
    // because the current continuation may contain this->Broadcast
133
8.40M
    m_Listeners[positionOfRemovedElement] = nullptr;
134
8.40M
    m_RemovedPositions.push_back(positionOfRemovedElement);
135
8.40M
}
136
137
void SfxBroadcaster::ForAllListeners(const std::function<bool(SfxListener*)>& f) const
138
627k
{
139
4.12M
    for (size_t i = 0; i < m_Listeners.size(); ++i)
140
3.51M
    {
141
3.51M
        SfxListener* const pListener = m_Listeners[i];
142
3.51M
        if (pListener)
143
3.26M
            if (f(pListener))
144
17.9k
                break;
145
3.51M
    }
146
627k
}
147
148
923k
bool SfxBroadcaster::HasListeners() const { return GetListenerCount() != 0; }
149
150
size_t SfxBroadcaster::GetListenerCount() const
151
923k
{
152
923k
    return m_Listeners.size() - m_RemovedPositions.size();
153
923k
}
154
155
0
bool SfxBroadcaster::IsSfxStyleSheet() const { return false; }
156
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */