LCOV - code coverage report
Current view: top level - src/engraving/infrastructure - rtti.h Coverage Total Hit
Test: filtered_coverage.info Lines: 90.0 % 20 18
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              : #pragma once
      23              : 
      24              : #include "log.h"
      25              : 
      26              : namespace mu::engraving {
      27              : #define DECLARE_CLASSOF(Type) \
      28              : public: \
      29              :     static bool classof(const ElementType type) noexcept { return type == Type; } \
      30              :     static bool classof(const EngravingObject * item) noexcept { return item->type() == Type; } \
      31              : 
      32              : template<typename To, typename From>
      33              : bool is_classof(From* p) noexcept
      34              : {
      35              :     using ResultType = std::remove_pointer_t<To>;
      36              :     return p ? ResultType::classof(p) : false;
      37              : }
      38              : 
      39              : enum class CastMode {
      40              :     CHECK = 0,  // should be correct; assert if still not
      41              :     BAD,        // known to be bad; don’t assert, we’ll fix it later
      42              :     MAYBE_BAD   // in this case it’s okay if type mismatch
      43              : };
      44              : 
      45              : template<typename To, typename From>
      46       867107 : To item_cast(From from, CastMode mode = CastMode::CHECK) noexcept
      47              : {
      48              :     if constexpr (std::is_same_v<From, void>) {
      49              :         return static_cast<To>(from);
      50              :     } else {
      51       867107 :         To casted = dynamic_cast<To>(from);
      52       867107 :         if (mode == CastMode::CHECK) {
      53       413131 :             if (!(casted || !from)) {
      54            0 :                 LOGE() << "[BAD CAST] from: " << typeid(From).name() << ", to: " << typeid(To).name();
      55              :             }
      56       413131 :             assert(casted || !from);
      57              :         }
      58       867107 :         return casted;
      59              :     }
      60              : }
      61              : }
      62              : 
      63              : namespace mu::engraving::rtti {
      64              : /* ===============================================
      65              : This visitor to foreaching the list of given types
      66              : How to use:
      67              : 1. Make types list:
      68              : using SomeTypeList = TypeList<ItemA, ItemB>;
      69              : 
      70              : 2. Create subclass like this, and implement the `doVisit` method:
      71              : class FooVisitor : public rtti::Visitor<FooVisitor>
      72              : {
      73              : public:
      74              :     template<typename T>
      75              :     static bool doVisit(EngravingItem* item, ...)
      76              :     {
      77              :         if (T::classof(item)) {
      78              :             ...
      79              :             return true;
      80              :         }
      81              :         return false;
      82              :     }
      83              : };
      84              : 
      85              : 3. Call the `visit` method:
      86              : 
      87              : FooVisitor::visit(SomeTypeList {}, item, ...);
      88              : 
      89              : */
      90              : 
      91              : template<typename ... Types> struct TypeList {};
      92              : 
      93              : template<typename Impl>
      94              : class Visitor
      95              : {
      96              : public:
      97              :     enum Policy {
      98              :         MayBeNotFound = 0,
      99              :         ShouldBeFound
     100              :     };
     101              : 
     102              :     template<typename ... Types, typename ... Args >
     103         8831 :     static bool visit(TypeList<Types...> types, Args&& ... args)
     104              :     {
     105         8831 :         return visit(Policy::MayBeNotFound, types, std::forward<Args>(args)...);
     106              :     }
     107              : 
     108              :     template<typename ... Types, typename ... Args >
     109         8831 :     static bool visit(Policy policy, TypeList<Types...> types, Args&& ... args)
     110              :     {
     111         8831 :         bool found = visit_helper(types, std::forward<Args>(args)...);
     112         8831 :         if (policy == Policy::ShouldBeFound) {
     113            0 :             DO_ASSERT(found);
     114              :         }
     115         8831 :         return found;
     116              :     }
     117              : 
     118              : private:
     119              :     template<typename ... Args>
     120         1059 :     static bool visit_helper(TypeList<>, Args&&...) { return false; }
     121              : 
     122              :     template<class Head, class ... Tail, typename ... Args>
     123       139692 :     static bool visit_helper(TypeList<Head, Tail...>, Args&& ... args)
     124              :     {
     125       139692 :         bool found = Impl::template doVisit<Head>(args ...);
     126       139692 :         if (!found) {
     127       131920 :             found = visit_helper(TypeList<Tail...> {}, std::forward<Args>(args)...);
     128              :         }
     129       139692 :         return found;
     130              :     }
     131              : };
     132              : }
        

Generated by: LCOV version 2.0-1