Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #ifndef MU_ENGRAVING_NOTIFIER_H
24 : #define MU_ENGRAVING_NOTIFIER_H
25 :
26 : #include "global/allocator.h"
27 :
28 : namespace mu::engraving {
29 : template<typename Data> class Notifier;
30 :
31 : //---------------------------------------------------------
32 : // Listener
33 : //---------------------------------------------------------
34 :
35 : template<typename Data>
36 : class Listener
37 : {
38 0 : OBJECT_ALLOCATOR(engraving, Listener)
39 :
40 : public:
41 16363 : Listener() = default;
42 : Listener(Notifier<Data>* n)
43 : : m_notifier(n) {}
44 : // do not copy notifier attachment
45 : Listener(const Listener<Data>&) {}
46 : Listener(Listener<Data>&&);
47 : Listener& operator=(const Listener<Data>&) { return *this; }
48 : Listener& operator=(Listener&&);
49 : virtual ~Listener();
50 :
51 : void setNotifier(Notifier<Data>* n);
52 :
53 19469 : void detachNotifier(Notifier<Data>* n)
54 : {
55 19469 : if (m_notifier == n) {
56 8139 : setNotifier(nullptr);
57 : }
58 19469 : }
59 :
60 22660 : Notifier<Data>* notifier() { return m_notifier; }
61 : const Notifier<Data>* notifier() const { return m_notifier; }
62 :
63 : virtual void receive(Data d) = 0;
64 :
65 : template<typename T>
66 : friend void swap(Listener<T>& l1, Listener<T>& l2);
67 :
68 : private:
69 : Notifier<Data>* m_notifier = nullptr;
70 : };
71 :
72 : //---------------------------------------------------------
73 : // Notifier
74 : //---------------------------------------------------------
75 :
76 : template<typename Data>
77 : class Notifier
78 : {
79 : public:
80 20355 : Notifier() = default;
81 : // do not copy listeners list
82 22477 : Notifier(const Notifier<Data>&) {}
83 0 : Notifier& operator=(const Notifier<Data>&) { return *this; }
84 20918 : ~Notifier()
85 : {
86 20918 : m_atChange = true; // we don't need to update listeners list anymore
87 24024 : for (Listener<Data>* l : m_listeners) {
88 3106 : l->detachNotifier(this);
89 : }
90 20918 : }
91 :
92 28984 : void addListener(Listener<Data>* l)
93 : {
94 28984 : if (m_atChange || !l) {
95 8827 : return;
96 : }
97 20157 : m_atChange = true;
98 20157 : m_listeners.push_back(l);
99 20157 : l->setNotifier(this);
100 20157 : m_atChange = false;
101 : }
102 :
103 24502 : void removeListener(Listener<Data>* l)
104 : {
105 24502 : if (m_atChange || !l) {
106 8139 : return;
107 : }
108 16363 : m_atChange = true;
109 16363 : m_listeners.erase(std::remove(m_listeners.begin(), m_listeners.end(), l), m_listeners.end());
110 16363 : l->detachNotifier(this);
111 16363 : m_atChange = false;
112 : }
113 :
114 15842 : void notify(Data d) const
115 : {
116 19634 : for (Listener<Data>* l : m_listeners) {
117 3792 : l->receive(d);
118 : }
119 15842 : }
120 :
121 : private:
122 :
123 : std::vector<Listener<Data>*> m_listeners;
124 : bool m_atChange = false;
125 : };
126 :
127 : template<typename Data>
128 : Listener<Data>::Listener(Listener<Data>&& other)
129 : {
130 : if (Notifier<Data>* n = other.notifier()) {
131 : n->removeListener(other);
132 : setNotifier(n);
133 : }
134 : }
135 :
136 : template<typename Data>
137 : Listener<Data>& Listener<Data>::operator=(Listener<Data>&& other)
138 : {
139 : if (Notifier<Data>* n = other.notifier()) {
140 : n->removeListener(other);
141 : setNotifier(n);
142 : } else {
143 : setNotifier(nullptr);
144 : }
145 :
146 : return *this;
147 : }
148 :
149 : template<typename Data>
150 19160 : Listener<Data>::~Listener()
151 : {
152 19160 : if (m_notifier) {
153 5033 : m_notifier->removeListener(this);
154 : }
155 19160 : }
156 :
157 : template<typename Data>
158 50956 : void Listener<Data>::setNotifier(Notifier<Data>* n)
159 : {
160 50956 : if (n == m_notifier) {
161 11330 : return;
162 : }
163 39626 : Notifier<Data>* oldNotifier = m_notifier;
164 39626 : m_notifier = n;
165 39626 : if (oldNotifier) {
166 19469 : oldNotifier->removeListener(this);
167 : }
168 39626 : if (m_notifier) {
169 20157 : m_notifier->addListener(this);
170 : }
171 : }
172 :
173 : template<typename Data>
174 11330 : void swap(Listener<Data>& l1, Listener<Data>& l2)
175 : {
176 11330 : Notifier<Data>* n1 = l1.notifier();
177 11330 : Notifier<Data>* n2 = l2.notifier();
178 11330 : l1.setNotifier(n2);
179 11330 : l2.setNotifier(n1);
180 11330 : }
181 : } // namespace mu::engraving
182 : #endif
|