From 4a422f4e54959303b0a6083650d2f19a25716a1a Mon Sep 17 00:00:00 2001 From: jacqueline Date: Mon, 23 Dec 2024 16:23:57 +1100 Subject: [PATCH] Use a common code path for parsing delimited track tags --- src/tangara/database/track.cpp | 116 +++++++++++++-------------------- 1 file changed, 46 insertions(+), 70 deletions(-) diff --git a/src/tangara/database/track.cpp b/src/tangara/database/track.cpp index f0959c98..9f7da2d5 100644 --- a/src/tangara/database/track.cpp +++ b/src/tangara/database/track.cpp @@ -94,6 +94,50 @@ auto tagToString(const TagValue& val) -> std::string { return ""; } +/* + * Utility for taking a string containing delimited tags, and splitting it out + * into a vector of individual tags. + */ +auto parseDelimitedTags(const std::string_view s, + const char* delimiters, + std::pmr::vector& out) -> void { + out.clear(); + std::string src = {s.data(), s.size()}; + char* token = std::strtok(src.data(), delimiters); + + auto trim_and_add = [&](std::string_view s) { + std::string copy = {s.data(), s.size()}; + + // Trim the left + copy.erase(copy.begin(), + std::find_if(copy.begin(), copy.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); + + // Trim the right + copy.erase(std::find_if(copy.rbegin(), copy.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + copy.end()); + + // Ignore empty strings. + if (!copy.empty()) { + out.push_back({copy.data(), copy.size()}); + } + }; + + if (token == NULL) { + // No delimiters found in the input. Treat this as a single result. + trim_and_add(s); + } else { + while (token != NULL) { + // Add tokens until no more delimiters found. + trim_and_add(token); + token = std::strtok(NULL, delimiters); + } + } +} + auto TrackTags::create() -> std::shared_ptr { return std::allocate_shared>( @@ -203,41 +247,7 @@ auto TrackTags::allArtists() const -> std::span { } auto TrackTags::allArtists(const std::string_view s) -> void { - allArtists_.clear(); - std::string src = {s.data(), s.size()}; - char* token = std::strtok(src.data(), kAllArtistDelimiters); - - auto trim_and_add = [this](std::string_view s) { - std::string copy = {s.data(), s.size()}; - - // Trim the left - copy.erase(copy.begin(), - std::find_if(copy.begin(), copy.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); - - // Trim the right - copy.erase(std::find_if(copy.rbegin(), copy.rend(), - [](unsigned char ch) { return !std::isspace(ch); }) - .base(), - copy.end()); - - // Ignore empty strings. - if (!copy.empty()) { - allArtists_.push_back({copy.data(), copy.size()}); - } - }; - - if (token == NULL) { - // No delimiters found in the input. Treat this as a single artist. - trim_and_add(s); - } else { - while (token != NULL) { - // Add tokens until no more delimiters found. - trim_and_add(token); - token = std::strtok(NULL, kAllArtistDelimiters); - } - } + parseDelimitedTags(s, kAllArtistDelimiters, allArtists_); } auto TrackTags::album() const -> const std::optional& { @@ -281,41 +291,7 @@ auto TrackTags::genres() const -> std::span { } auto TrackTags::genres(const std::string_view s) -> void { - genres_.clear(); - std::string src = {s.data(), s.size()}; - char* token = std::strtok(src.data(), kGenreDelimiters); - - auto trim_and_add = [this](std::string_view s) { - std::string copy = {s.data(), s.size()}; - - // Trim the left - copy.erase(copy.begin(), - std::find_if(copy.begin(), copy.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); - - // Trim the right - copy.erase(std::find_if(copy.rbegin(), copy.rend(), - [](unsigned char ch) { return !std::isspace(ch); }) - .base(), - copy.end()); - - // Ignore empty strings. - if (!copy.empty()) { - genres_.push_back({copy.data(), copy.size()}); - } - }; - - if (token == NULL) { - // No delimiters found in the input. Treat this as a single genre. - trim_and_add(s); - } else { - while (token != NULL) { - // Add tokens until no more delimiters found. - trim_and_add(token); - token = std::strtok(NULL, kGenreDelimiters); - } - } + parseDelimitedTags(s, kGenreDelimiters, genres_); } /*