LCOV - code coverage report
Current view: top level - src/engraving/dom - notifier.h Coverage Total Hit
Test: filtered_coverage.info Lines: 96.2 % 52 50
Test Date: 2026-11-05 04:07:02

            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
        

Generated by: LCOV version 2.0-1