LCOV - code coverage report
Current view: top level - muse/framework/global - containers.h Coverage Total Hit
Test: filtered_coverage.info Lines: 82.1 % 184 151
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-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 <algorithm>
      25              : #include <vector>
      26              : #include <list>
      27              : #include <set>
      28              : #include <unordered_set>
      29              : #include <map>
      30              : #include <unordered_map>
      31              : 
      32              : //! NOTE useful functions for containers
      33              : 
      34              : namespace muse {
      35              : static constexpr size_t nidx = static_cast<size_t>(-1);
      36              : 
      37              : // vector
      38              : template<typename T>
      39      2808643 : inline bool contains(const std::vector<T>& vec, const T& v)
      40              : {
      41      2808643 :     return std::find(vec.cbegin(), vec.cend(), v) != vec.cend();
      42              : }
      43              : 
      44              : template<typename T, typename Predicate>
      45          404 : inline bool contains_if(const std::vector<T>& vec, Predicate&& pred)
      46              : {
      47          404 :     return std::find_if(vec.cbegin(), vec.cend(), std::forward<Predicate>(pred)) != vec.cend();
      48              : }
      49              : 
      50              : template<typename T>
      51       180557 : inline T value(const std::vector<T>& vec, size_t idx)
      52              : {
      53       180557 :     if (idx < vec.size()) {
      54       180557 :         return vec.at(idx);
      55              :     }
      56              : 
      57              :     if constexpr (std::is_pointer<T>::value) {
      58            0 :         return nullptr;
      59              :     } else {
      60            0 :         return T();
      61              :     }
      62              : }
      63              : 
      64              : template<typename T>
      65       248081 : inline bool remove(std::vector<T>& vec, const T& v)
      66              : {
      67       248081 :     size_t origSize = vec.size();
      68       248081 :     vec.erase(std::remove(vec.begin(), vec.end(), v), vec.end());
      69       248081 :     return origSize != vec.size();
      70              : }
      71              : 
      72              : template<typename T, typename Predicate>
      73         4396 : inline bool remove_if(std::vector<T>& vec, Predicate p)
      74              : {
      75         4396 :     size_t origSize = vec.size();
      76         4396 :     vec.erase(std::remove_if(vec.begin(), vec.end(), p), vec.end());
      77         4396 :     return origSize != vec.size();
      78              : }
      79              : 
      80              : template<typename T>
      81              : inline void removeFirst(std::vector<T>& vec)
      82              : {
      83              :     vec.erase(vec.begin());
      84              : }
      85              : 
      86              : template<typename T>
      87       166687 : inline T takeAt(std::vector<T>& vec, size_t idx)
      88              : {
      89       166687 :     T v = value(vec, idx);
      90       166687 :     vec.erase(vec.begin() + idx);
      91       166687 :     return v;
      92            0 : }
      93              : 
      94              : template<typename T>
      95         1716 : inline T takeFirst(std::vector<T>& vec)
      96              : {
      97         1716 :     return takeAt(vec, 0);
      98              : }
      99              : 
     100              : template<typename T>
     101       163487 : inline T takeLast(std::vector<T>& vec)
     102              : {
     103       163487 :     return takeAt(vec, vec.size() - 1);
     104              : }
     105              : 
     106              : template<typename T>
     107            0 : inline void swapItemsAt(std::vector<T>& vec, size_t idx1, size_t idx2)
     108              : {
     109            0 :     T v1 = vec[idx1];
     110            0 :     vec[idx1] = vec[idx2];
     111            0 :     vec[idx2] = v1;
     112            0 : }
     113              : 
     114              : template<typename T>
     115            4 : inline bool moveItem(std::vector<T>& vec, size_t oldIdx, size_t newIdx)
     116              : {
     117            4 :     if (oldIdx == muse::nidx || oldIdx == newIdx) {
     118            1 :         return false;
     119              :     }
     120              : 
     121            3 :     newIdx = std::min(vec.size() - 1, newIdx);
     122              : 
     123            3 :     if (oldIdx > newIdx) {
     124            1 :         std::rotate(vec.rend() - oldIdx - 1, vec.rend() - oldIdx, vec.rend() - newIdx);
     125              :     } else {
     126            2 :         std::rotate(vec.begin() + oldIdx, vec.begin() + oldIdx + 1, vec.begin() + newIdx + 1);
     127              :     }
     128              : 
     129            3 :     return true;
     130              : }
     131              : 
     132              : template<typename T>
     133          591 : std::vector<T> mid(const std::vector<T>& c, size_t pos, int alength = -1)
     134              : {
     135          591 :     if (c.empty()) {
     136            0 :         return std::vector<T>();
     137              :     }
     138              : 
     139          591 :     size_t end = 0;
     140          591 :     if (alength < 0) {
     141          591 :         end = c.size();
     142              :     } else {
     143            0 :         end = pos + static_cast<size_t>(alength);
     144              :     }
     145              : 
     146          591 :     if (end > (c.size())) {
     147            0 :         end = c.size();
     148              :     }
     149              : 
     150          591 :     if (end == 0) {
     151            0 :         return std::vector<T>();
     152              :     }
     153              : 
     154          591 :     if (pos >= end) {
     155            0 :         return std::vector<T>();
     156              :     }
     157              : 
     158          591 :     std::vector<T> sub(c.begin() + pos, c.begin() + end);
     159          591 :     return sub;
     160          591 : }
     161              : 
     162              : template<typename T>
     163          117 : inline void join(std::vector<T>& l1, const std::vector<T>& l2)
     164              : {
     165          117 :     l1.insert(l1.end(), l2.begin(), l2.end());
     166          117 : }
     167              : 
     168              : // list
     169              : template<typename T>
     170         7729 : inline bool contains(const std::list<T>& l, const T& v)
     171              : {
     172         7729 :     return std::find(l.cbegin(), l.cend(), v) != l.cend();
     173              : }
     174              : 
     175              : template<typename T>
     176            0 : inline void join(std::list<T>& l1, const std::list<T>& l2)
     177              : {
     178            0 :     l1.insert(l1.end(), l2.begin(), l2.end());
     179            0 : }
     180              : 
     181              : template<typename T>
     182         1487 : inline bool remove(std::list<T>& l, const T& v)
     183              : {
     184         1487 :     if (!contains(l, v)) {
     185            0 :         return false;
     186              :     }
     187         1487 :     l.remove(v);
     188         1487 :     return true;
     189              : }
     190              : 
     191              : template<typename T>
     192              : inline T takeFirst(std::list<T>& l)
     193              : {
     194              :     T v = l.front();
     195              :     l.pop_front();
     196              :     return v;
     197              : }
     198              : 
     199              : template<typename T>
     200              : inline T takeLast(std::list<T>& l)
     201              : {
     202              :     T v = l.back();
     203              :     l.pop_back();
     204              :     return v;
     205              : }
     206              : 
     207              : template<typename T>
     208              : inline std::pair<bool, T> take(std::list<T>& l, const T& v)
     209              : {
     210              :     auto it = std::find(l.begin(), l.end(), v);
     211              :     if (it == l.end()) {
     212              :         return std::make_pair(false, T());
     213              :     }
     214              :     std::pair<bool, T> ret = std::make_pair(true, *it);
     215              :     l.erase(it);
     216              :     return ret;
     217              : }
     218              : 
     219              : // ===========================
     220              : // Set
     221              : // ===========================
     222              : template<typename T>
     223       116238 : inline bool contains(const std::set<T>& s, const T& v)
     224              : {
     225       116238 :     return s.find(v) != s.cend();
     226              : }
     227              : 
     228              : template<typename T>
     229      3472488 : inline bool contains(const std::unordered_set<T>& s, const T& v)
     230              : {
     231      3472488 :     return s.find(v) != s.cend();
     232              : }
     233              : 
     234              : // ===========================
     235              : // Array
     236              : // ===========================
     237              : template<typename T, size_t size>
     238         1391 : inline bool contains(const std::array<T, size>& s, const T& v)
     239              : {
     240         1391 :     return std::find(s.begin(), s.end(), v) != s.cend();
     241              : }
     242              : 
     243              : // ===========================
     244              : // General
     245              : // ===========================
     246              : 
     247              : template<typename Container, typename T>
     248       394464 : inline size_t indexOf(const Container& c, const T& v)
     249              : {
     250       394464 :     auto it = std::find(c.cbegin(), c.cend(), v);
     251       394464 :     if (it != c.cend()) {
     252       788756 :         return std::distance(c.cbegin(), it);
     253              :     }
     254           86 :     return muse::nidx;
     255              : }
     256              : 
     257              : template<typename K, typename V>
     258       105513 : inline bool contains(const std::map<K, V>& m, const K& k)
     259              : {
     260       105513 :     return m.find(k) != m.cend();
     261              : }
     262              : 
     263              : template<typename K, typename V>
     264           12 : inline bool contains(const std::multimap<K, V>& m, const K& k)
     265              : {
     266           12 :     return m.find(k) != m.cend();
     267              : }
     268              : 
     269              : template<typename K, typename V>
     270       534228 : inline bool contains(const std::unordered_map<K, V>& m, const K& k)
     271              : {
     272       534228 :     return m.find(k) != m.cend();
     273              : }
     274              : 
     275              : template<typename Map>
     276         7116 : inline auto values(const Map& m) -> std::vector<typename Map::mapped_type>
     277              : {
     278         7116 :     std::vector<typename Map::mapped_type> result;
     279         7116 :     result.reserve(m.size());
     280         7243 :     for (const auto& p : m) {
     281          127 :         result.push_back(p.second);
     282              :     }
     283         7116 :     return result;
     284            0 : }
     285              : 
     286              : template<typename Map, typename V, typename K>
     287         4240 : inline K key(const Map& m, const V& v, const K& def)
     288              : {
     289        21721 :     for (const auto& p : m) {
     290        20735 :         if (p.second == v) {
     291         3254 :             return p.first;
     292              :         }
     293              :     }
     294          986 :     return def;
     295              : }
     296              : 
     297              : template<typename Map, typename V>
     298           22 : inline auto key(const Map& m, const V& v) -> typename Map::key_type
     299              : {
     300         1732 :     for (const auto& p : m) {
     301         1732 :         if (p.second == v) {
     302           22 :             return p.first;
     303              :         }
     304              :     }
     305            0 :     typename Map::key_type def {};
     306            0 :     return def;
     307            0 : }
     308              : 
     309              : template<typename Map>
     310       146236 : inline auto value(const Map& m, const typename Map::key_type& k) -> typename Map::mapped_type
     311              : {
     312       146236 :     auto it = m.find(k);
     313       146236 :     if (it != m.end()) {
     314       104990 :         return it->second;
     315              :     }
     316        41246 :     typename Map::mapped_type def {};
     317        41246 :     return def;
     318        41244 : }
     319              : 
     320              : template<typename Map>
     321      2557744 : inline auto value(const Map& m, const typename Map::key_type& k, const typename Map::mapped_type& def) -> typename Map::mapped_type
     322              : {
     323      2557744 :     auto it = m.find(k);
     324      2557744 :     if (it != m.end()) {
     325       158990 :         return it->second;
     326              :     }
     327      2398754 :     return def;
     328              : }
     329              : 
     330              : template<typename Map, typename T>
     331          131 : inline bool remove(Map& c, const T& k)
     332              : {
     333          131 :     auto it = c.find(k);
     334          131 :     if (it != c.end()) {
     335           61 :         c.erase(it);
     336           61 :         return true;
     337              :     }
     338           70 :     return false;
     339              : }
     340              : 
     341              : template<typename Map, typename Predicate>
     342           11 : inline size_t remove_if(Map& c, Predicate pred)
     343              : {
     344           11 :     auto old_size = c.size();
     345           11 :     for (auto first = c.begin(), last = c.end(); first != last;) {
     346            0 :         if (pred(*first)) {
     347            0 :             first = c.erase(first);
     348              :         } else {
     349            0 :             ++first;
     350              :         }
     351              :     }
     352           11 :     return old_size - c.size();
     353              : }
     354              : 
     355              : template<typename Map, typename K>
     356         4668 : inline auto take(Map& m, const K& k) -> typename Map::mapped_type
     357              : {
     358         4668 :     auto it = m.find(k);
     359         4668 :     if (it != m.end()) {
     360         4668 :         auto v = it->second;
     361         4668 :         m.erase(it);
     362         4668 :         return v;
     363            0 :     }
     364            0 :     typename Map::mapped_type def {};
     365            0 :     return def;
     366            0 : }
     367              : 
     368              : template<typename K, typename V>
     369         1864 : inline std::set<K> uniqueKeys(const std::multimap<K, V>& mm)
     370              : {
     371         1864 :     std::set<K> keys;
     372         2212 :     for (auto it = mm.begin(); it != mm.end(); ++it) {
     373          348 :         keys.insert(it->first);
     374              :     }
     375         1864 :     return keys;
     376            0 : }
     377              : 
     378              : template<typename K, typename V>
     379        18626 : inline auto values(const std::multimap<K, V>& mm, const K& key) -> std::vector<typename std::multimap<K, V>::mapped_type>
     380              : {
     381        18626 :     std::vector<typename std::multimap<K, V>::mapped_type> result;
     382        18626 :     const auto range = mm.equal_range(key);
     383        29789 :     for (auto it = range.first; it != range.second; ++it) {
     384        11163 :         result.push_back(it->second);
     385              :     }
     386        18626 :     return result;
     387            0 : }
     388              : 
     389              : template<typename Container>
     390         9495 : inline typename Container::const_iterator findLessOrEqual(const Container& c, const typename Container::key_type& k)
     391              : {
     392         9495 :     if (c.empty()) {
     393         3769 :         return c.cend();
     394              :     }
     395              : 
     396         5726 :     auto it = c.upper_bound(k);
     397         5726 :     if (it == c.cbegin()) {
     398         2507 :         return c.cend();
     399              :     }
     400              : 
     401         3219 :     return std::prev(it);
     402              : }
     403              : 
     404              : template<typename Container>
     405          117 : inline typename Container::iterator findLessOrEqual(Container& c, const typename Container::key_type& k)
     406              : {
     407          117 :     if (c.empty()) {
     408           89 :         return c.end();
     409              :     }
     410              : 
     411           28 :     auto it = c.upper_bound(k);
     412           28 :     if (it == c.begin()) {
     413            5 :         return c.end();
     414              :     }
     415              : 
     416           23 :     return std::prev(it);
     417              : }
     418              : 
     419              : template<typename Container>
     420              : inline typename Container::const_iterator findLess(const Container& c, const typename Container::key_type& k)
     421              : {
     422              :     if (c.empty()) {
     423              :         return c.cend();
     424              :     }
     425              : 
     426              :     auto it = c.lower_bound(k);
     427              :     if (it == c.cbegin()) {
     428              :         return c.cend();
     429              :     }
     430              : 
     431              :     return std::prev(it);
     432              : }
     433              : 
     434              : template<typename Container>
     435          505 : inline typename Container::iterator findLess(Container& c, const typename Container::key_type& k)
     436              : {
     437          505 :     if (c.empty()) {
     438          463 :         return c.end();
     439              :     }
     440              : 
     441           42 :     auto it = c.lower_bound(k);
     442           42 :     if (it == c.begin()) {
     443           22 :         return c.end();
     444              :     }
     445              : 
     446           20 :     return std::prev(it);
     447              : }
     448              : 
     449              : template<typename ForwardIterator>
     450       665569 : inline void DeleteAll(ForwardIterator begin, ForwardIterator end)
     451              : {
     452       972226 :     while (begin != end) {
     453       306657 :         delete *begin;
     454       306657 :         ++begin;
     455              :     }
     456       665569 : }
     457              : 
     458              : template<typename Container>
     459       665569 : inline void DeleteAll(const Container& c)
     460              : {
     461       665569 :     DeleteAll(c.begin(), c.end());
     462       665569 : }
     463              : }
     464              : 
     465              : template<typename T>
     466            0 : inline std::set<T>& operator<<(std::set<T>& s, const T& v)
     467              : {
     468            0 :     s.insert(v);
     469            0 :     return s;
     470              : }
        

Generated by: LCOV version 2.0-1