From 93bf99f6396a34ec39c15c8580ba20e6e4f00faf Mon Sep 17 00:00:00 2001 From: gd Date: Wed, 29 Jan 2025 15:52:19 +0200 Subject: [PATCH 1/6] util/DereferenceIterator, TerminatedArray: added operator-(const IteratorType&) to DereferenceIterator and TerminatedArray::iterator It is required by std::distance and some std algos. --- src/util/DereferenceIterator.hxx | 4 ++++ src/util/TerminatedArray.hxx | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/util/DereferenceIterator.hxx b/src/util/DereferenceIterator.hxx index 4d21cd998e..c40ea55feb 100644 --- a/src/util/DereferenceIterator.hxx +++ b/src/util/DereferenceIterator.hxx @@ -82,6 +82,10 @@ public: return DereferenceIterator{original - n}; } + constexpr auto operator-(const DereferenceIterator& other) const noexcept { + return std::distance(other.original, original); + } + /* this is a template to allow comparisons with sentinel end iterators */ template diff --git a/src/util/TerminatedArray.hxx b/src/util/TerminatedArray.hxx index b0d361f66a..38d40c9ee6 100644 --- a/src/util/TerminatedArray.hxx +++ b/src/util/TerminatedArray.hxx @@ -101,6 +101,10 @@ public: return iterator{cursor - n}; } + constexpr auto operator-(const iterator& other) const noexcept { + return std::distance(other.cursor, cursor); + } + reference operator*() const noexcept { return *cursor; } From 3e9c2cce718c310b5ceefcffbb5cca28f6319980 Mon Sep 17 00:00:00 2001 From: gd Date: Wed, 29 Jan 2025 08:34:03 +0200 Subject: [PATCH 2/6] tag/Item: added operator== to TagItem --- src/tag/Item.hxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tag/Item.hxx b/src/tag/Item.hxx index 84bf6ae497..ea9385a28b 100644 --- a/src/tag/Item.hxx +++ b/src/tag/Item.hxx @@ -5,6 +5,7 @@ #define MPD_TAG_ITEM_HXX #include +#include enum TagType : uint8_t; @@ -22,6 +23,11 @@ struct TagItem { */ char value[1]; + bool operator==(const TagItem &other) const noexcept { + return (this == &other) ? true : + type == other.type && std::strcmp(value, other.value) == 0; + } + TagItem() = default; TagItem(const TagItem &other) = delete; TagItem &operator=(const TagItem &other) = delete; From 2a9c3a2e5059d84bdfe4eefda5e65c514f7964c3 Mon Sep 17 00:00:00 2001 From: gd Date: Wed, 29 Jan 2025 08:31:19 +0200 Subject: [PATCH 3/6] tag/Tag: added operator==(Tag&) --- src/tag/Tag.cxx | 9 +++++++++ src/tag/Tag.hxx | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/tag/Tag.cxx b/src/tag/Tag.cxx index 585862c36e..4ca50b878d 100644 --- a/src/tag/Tag.cxx +++ b/src/tag/Tag.cxx @@ -7,6 +7,15 @@ #include +bool +Tag::operator==(const Tag &other) const noexcept { + return (this == &other) ? true : + duration == other.duration + && has_playlist == other.has_playlist + && num_items == other.num_items + && std::equal(begin(), end(), other.begin(), other.end()); +} + void Tag::Clear() noexcept { diff --git a/src/tag/Tag.hxx b/src/tag/Tag.hxx index 6d6c368af7..dbfdb49f19 100644 --- a/src/tag/Tag.hxx +++ b/src/tag/Tag.hxx @@ -65,6 +65,8 @@ struct Tag { return *this; } + bool operator==(const Tag &other) const noexcept; + /** * Similar to the move operator, but move only the #TagItem * array. From f15014b6af1ded2bd39109c8750379f9497ea565 Mon Sep 17 00:00:00 2001 From: gd Date: Wed, 29 Jan 2025 08:39:32 +0200 Subject: [PATCH 4/6] tag/Item: made TagItem constructor private and friend TagPoolItem To only allow construction as part of TagPoolItem with its special var size allocator in TagPoolItem::Create. --- src/tag/Item.hxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tag/Item.hxx b/src/tag/Item.hxx index ea9385a28b..b67eac4699 100644 --- a/src/tag/Item.hxx +++ b/src/tag/Item.hxx @@ -28,6 +28,10 @@ struct TagItem { type == other.type && std::strcmp(value, other.value) == 0; } +private: + /* making the constructor private + to only allow construction by TagPoolItem. */ + friend struct TagPoolItem; TagItem() = default; TagItem(const TagItem &other) = delete; TagItem &operator=(const TagItem &other) = delete; From f9d47502d820a90b5210e404ba383767e8540676 Mon Sep 17 00:00:00 2001 From: gd Date: Wed, 29 Jan 2025 08:43:51 +0200 Subject: [PATCH 5/6] player/Thread: update song tag from remote stream only if changed. Some streams send the same tags frequently, causing unnecessary player queue update events. --- src/player/Thread.cxx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx index 1a9de72355..5980f4748c 100644 --- a/src/player/Thread.cxx +++ b/src/player/Thread.cxx @@ -904,13 +904,15 @@ PlayerControl::LockUpdateSongTag(DetachedSong &song, streams may change tags dynamically */ return; - song.SetTag(new_tag); + if (new_tag != song.GetTag()) { + song.SetTag(new_tag); - LockSetTaggedSong(song); + LockSetTaggedSong(song); - /* the main thread will update the playlist version when he - receives this event */ - listener.OnPlayerTagModified(); + /* the main thread will update the playlist version when he + receives this event */ + listener.OnPlayerTagModified(); + } } inline void From ce9ee38304af932c65bd6e1d6591dc3c3552e7d7 Mon Sep 17 00:00:00 2001 From: gd Date: Wed, 29 Jan 2025 08:45:21 +0200 Subject: [PATCH 6/6] decoder/Bridge: DecoderBridge::UpdateStreamTag - return false if stream tag not changed. Some streams send the same tags frequently, causeing unnecessary update events. --- src/decoder/Bridge.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/decoder/Bridge.cxx b/src/decoder/Bridge.cxx index 78a222e70a..0eec4a1d13 100644 --- a/src/decoder/Bridge.cxx +++ b/src/decoder/Bridge.cxx @@ -239,6 +239,10 @@ DecoderBridge::UpdateStreamTag(InputStream *is) noexcept /* discard the song tag; we don't need it */ song_tag.reset(); + if (stream_tag && tag && *stream_tag == *tag) + /* not changed */ + return false; + stream_tag = std::move(tag); return true; }