From c911efd6036c78249b250f8daf6a5ad0e83fdd3b Mon Sep 17 00:00:00 2001 From: Joachim Schmitz Date: Fri, 26 Jan 2024 16:24:19 +0100 Subject: [PATCH] Add containers helpers Backport of #21205, part 0 (i.e. the prerequisites) --- global/containers.h | 453 +++++++++++++++++++ importexport/musicxml/importmxmlpass1.cpp | 2 + importexport/musicxml/importmxmlpass1.h | 2 + importexport/musicxml/importmxmlpass2.cpp | 2 + importexport/musicxml/importxmlfirstpass.cpp | 2 + importexport/musicxml/musicxmlsupport.cpp | 2 + 6 files changed, 463 insertions(+) create mode 100644 global/containers.h diff --git a/global/containers.h b/global/containers.h new file mode 100644 index 0000000000000..7f96fca82bcc7 --- /dev/null +++ b/global/containers.h @@ -0,0 +1,453 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef MU_GLOBAL_CONTAINERS_H +#define MU_GLOBAL_CONTAINERS_H + +#include +#include +#include +#include +#include +#include +#include + +//! NOTE useful functions for containers + +namespace mu { +static constexpr size_t nidx = static_cast(-1); + +// vector +template +inline bool contains(const std::vector& vec, const T& v) +{ + return std::find(vec.cbegin(), vec.cend(), v) != vec.cend(); +} + +template +inline T value(const std::vector& vec, size_t idx) +{ + if (idx < vec.size()) { + return vec.at(idx); + } + + if /*constexpr*/ (std::is_pointer::value) { + return nullptr; + } else { + return T(); + } +} + +template +inline bool remove(std::vector& vec, const T& v) +{ + size_t origSize = vec.size(); + vec.erase(std::remove(vec.begin(), vec.end(), v), vec.end()); + return origSize != vec.size(); +} + +template +inline bool remove_if(std::vector& vec, Predicate p) +{ + size_t origSize = vec.size(); + vec.erase(std::remove_if(vec.begin(), vec.end(), p), vec.end()); + return origSize != vec.size(); +} + +template +inline void removeFirst(std::vector& vec) +{ + vec.erase(vec.begin()); +} + +template +inline T takeAt(std::vector& vec, size_t idx) +{ + T v = value(vec, idx); + vec.erase(vec.begin() + idx); + return v; +} + +template +inline T takeFirst(std::vector& vec) +{ + return takeAt(vec, 0); +} + +template +inline T takeLast(std::vector& vec) +{ + return takeAt(vec, vec.size() - 1); +} + +template +inline void swapItemsAt(std::vector& vec, size_t idx1, size_t idx2) +{ + T v1 = vec[idx1]; + vec[idx1] = vec[idx2]; + vec[idx2] = v1; +} + +template +inline bool moveItem(std::vector& vec, size_t oldIdx, size_t newIdx) +{ + if (oldIdx == mu::nidx || oldIdx == newIdx) { + return false; + } + + newIdx = std::min(vec.size() - 1, newIdx); + + if (oldIdx > newIdx) { + std::rotate(vec.rend() - oldIdx - 1, vec.rend() - oldIdx, vec.rend() - newIdx); + } else { + std::rotate(vec.begin() + oldIdx, vec.begin() + oldIdx + 1, vec.begin() + newIdx + 1); + } + + return true; +} + +template +std::vector mid(const std::vector& c, size_t pos, int alength = -1) +{ + if (c.empty()) { + return std::vector(); + } + + size_t end = 0; + if (alength < 0) { + end = c.size(); + } else { + end = pos + static_cast(alength); + } + + if (end > (c.size())) { + end = c.size(); + } + + if (end == 0) { + return std::vector(); + } + + if (pos >= end) { + return std::vector(); + } + + std::vector sub(c.begin() + pos, c.begin() + end); + return sub; +} + +template +inline void join(std::vector& l1, const std::vector& l2) +{ + l1.insert(l1.end(), l2.begin(), l2.end()); +} + +// list +template +inline bool contains(const std::list& l, const T& v) +{ + return std::find(l.cbegin(), l.cend(), v) != l.cend(); +} + +template +inline void join(std::list& l1, const std::list& l2) +{ + l1.insert(l1.end(), l2.begin(), l2.end()); +} + +template +inline bool remove(std::list& l, const T& v) +{ + if (!contains(l, v)) { + return false; + } + l.remove(v); + return true; +} + +template +inline T takeFirst(std::list& l) +{ + T v = l.front(); + l.pop_front(); + return v; +} + +template +inline T takeLast(std::list& l) +{ + T v = l.back(); + l.pop_back(); + return v; +} + +template +inline std::pair take(std::list& l, const T& v) +{ + auto it = std::find(l.begin(), l.end(), v); + if (it == l.end()) { + return std::make_pair(false, T()); + } + std::pair ret = std::make_pair(true, *it); + l.erase(it); + return ret; +} + +// =========================== +// Set +// =========================== +template +inline bool contains(const std::set& s, const T& v) +{ + return s.find(v) != s.cend(); +} + +template +inline bool contains(const std::unordered_set& s, const T& v) +{ + return s.find(v) != s.cend(); +} + +// =========================== +// General +// =========================== + +template +inline size_t indexOf(const Container& c, const T& v) +{ + auto it = std::find(c.cbegin(), c.cend(), v); + if (it != c.cend()) { + return std::distance(c.cbegin(), it); + } + return mu::nidx; +} + +template +inline bool contains(const std::map& m, const K& k) +{ + return m.find(k) != m.cend(); +} + +template +inline bool contains(const std::multimap& m, const K& k) +{ + return m.find(k) != m.cend(); +} + +template +inline bool contains(const std::unordered_map& m, const K& k) +{ + return m.find(k) != m.cend(); +} + +template +inline auto keys(const Map& m) -> std::vector +{ + std::vector result; + for (auto&& p : m) { + result.push_back(p.first); + } + return result; +} + +template +inline auto values(const Map& m) -> std::vector +{ + std::vector result; + for (auto&& p : m) { + result.push_back(p.second); + } + return result; +} + +template +inline K key(const Map& m, const V& v, const K& def) +{ + for (const auto& p : m) { + if (p.second == v) { + return p.first; + } + } + return def; +} + +template +inline auto key(const Map& m, const V& v) -> typename Map::key_type +{ + for (const auto& p : m) { + if (p.second == v) { + return p.first; + } + } + typename Map::key_type def {}; + return def; +} + +template +inline auto value(const Map& m, const typename Map::key_type& k) -> typename Map::mapped_type +{ + auto it = m.find(k); + if (it != m.end()) { + return it->second; + } + typename Map::mapped_type def {}; + return def; +} + +template +inline auto value(const Map& m, const typename Map::key_type& k, const typename Map::mapped_type& def) -> typename Map::mapped_type +{ + auto it = m.find(k); + if (it != m.end()) { + return it->second; + } + return def; +} + +template +inline bool remove(Map& c, const T& k) +{ + auto it = c.find(k); + if (it != c.end()) { + c.erase(it); + return true; + } + return false; +} + +template +inline auto take(Map& m, const K& k) -> typename Map::mapped_type +{ + auto it = m.find(k); + if (it != m.end()) { + auto v = it->second; + m.erase(it); + return v; + } + typename Map::mapped_type def {}; + return def; +} + +template +inline std::set uniqueKeys(const std::multimap& mm) +{ + std::set keys; + for (auto it = mm.begin(); it != mm.end(); ++it) { + keys.insert(it->first); + } + return keys; +} + +template +inline auto values(const std::multimap& mm, const K& key) -> std::vector::mapped_type> +{ + std::vector::mapped_type> result; + const auto range = mm.equal_range(key); + for (auto it = range.first; it != range.second; ++it) { + result.push_back(it->second); + } + return result; +} + +template +inline typename C::const_iterator findLessOrEqual(const C& c, const typename C::key_type& k) +{ + if (c.empty()) { + return c.cend(); + } + + auto it = c.upper_bound(k); + if (it == c.cbegin()) { + return c.cend(); + } + + return std::prev(it); +} + +template +inline typename C::iterator findLessOrEqual(C& c, const typename C::key_type& k) +{ + if (c.empty()) { + return c.end(); + } + + auto it = c.upper_bound(k); + if (it == c.begin()) { + return c.end(); + } + + return std::prev(it); +} + +template +inline typename C::const_iterator findLess(const C& c, const typename C::key_type& k) +{ + if (c.empty()) { + return c.cend(); + } + + auto it = c.lower_bound(k); + if (it == c.cbegin()) { + return c.cend(); + } + + return std::prev(it); +} + +template +inline typename C::iterator findLess(C& c, const typename C::key_type& k) +{ + if (c.empty()) { + return c.end(); + } + + auto it = c.lower_bound(k); + if (it == c.begin()) { + return c.end(); + } + + return std::prev(it); +} + +template +inline void DeleteAll(ForwardIterator begin, ForwardIterator end) +{ + while (begin != end) { + delete *begin; + ++begin; + } +} + +template +inline void DeleteAll(const Container& c) +{ + DeleteAll(c.begin(), c.end()); +} +} + +template +inline std::set& operator<<(std::set& s, const T& v) +{ + s.insert(v); + return s; +} + +#endif // MU_GLOBAL_CONTAINERS_H diff --git a/importexport/musicxml/importmxmlpass1.cpp b/importexport/musicxml/importmxmlpass1.cpp index c34cda64fa45b..45907b8b7bd10 100644 --- a/importexport/musicxml/importmxmlpass1.cpp +++ b/importexport/musicxml/importmxmlpass1.cpp @@ -17,6 +17,8 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. //============================================================================= +#include "global/containers.h" + #include "libmscore/box.h" #include "libmscore/chordrest.h" #include "libmscore/instrtemplate.h" diff --git a/importexport/musicxml/importmxmlpass1.h b/importexport/musicxml/importmxmlpass1.h index 417a5c4b903dd..cad5f0c919dc2 100644 --- a/importexport/musicxml/importmxmlpass1.h +++ b/importexport/musicxml/importmxmlpass1.h @@ -20,6 +20,8 @@ #ifndef __IMPORTMXMLPASS1_H__ #define __IMPORTMXMLPASS1_H__ +#include "global/containers.h" + #include "libmscore/score.h" #include "importxmlfirstpass.h" #include "musicxml.h" // for the creditwords and MusicXmlPartGroupList definitions diff --git a/importexport/musicxml/importmxmlpass2.cpp b/importexport/musicxml/importmxmlpass2.cpp index 52e72097cf8ed..6971dfe9fcdb3 100644 --- a/importexport/musicxml/importmxmlpass2.cpp +++ b/importexport/musicxml/importmxmlpass2.cpp @@ -20,6 +20,8 @@ #include #include +#include "global/containers.h" + #include "libmscore/arpeggio.h" #include "libmscore/accidental.h" #include "libmscore/box.h" diff --git a/importexport/musicxml/importxmlfirstpass.cpp b/importexport/musicxml/importxmlfirstpass.cpp index 4799064500dda..effe652717c82 100644 --- a/importexport/musicxml/importxmlfirstpass.cpp +++ b/importexport/musicxml/importxmlfirstpass.cpp @@ -10,6 +10,8 @@ // the file LICENCE.GPL //============================================================================= +#include "global/containers.h" + #include "importxmlfirstpass.h" namespace Ms { diff --git a/importexport/musicxml/musicxmlsupport.cpp b/importexport/musicxml/musicxmlsupport.cpp index c9f7636a8952d..128703235a212 100644 --- a/importexport/musicxml/musicxmlsupport.cpp +++ b/importexport/musicxml/musicxmlsupport.cpp @@ -21,6 +21,8 @@ MusicXML support. */ +#include "global/containers.h" + //#include "libmscore/accidental.h" #include "libmscore/articulation.h" #include "libmscore/chord.h"