Use a common code path for parsing delimited track tags

custom
jacqueline 4 months ago
parent e9e608cfa0
commit 4a422f4e54
  1. 116
      src/tangara/database/track.cpp

@ -94,6 +94,50 @@ auto tagToString(const TagValue& val) -> std::string {
return ""; 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<std::pmr::string>& 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<TrackTags> { auto TrackTags::create() -> std::shared_ptr<TrackTags> {
return std::allocate_shared<TrackTags, return std::allocate_shared<TrackTags,
std::pmr::polymorphic_allocator<TrackTags>>( std::pmr::polymorphic_allocator<TrackTags>>(
@ -203,41 +247,7 @@ auto TrackTags::allArtists() const -> std::span<const std::pmr::string> {
} }
auto TrackTags::allArtists(const std::string_view s) -> void { auto TrackTags::allArtists(const std::string_view s) -> void {
allArtists_.clear(); parseDelimitedTags(s, kAllArtistDelimiters, allArtists_);
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);
}
}
} }
auto TrackTags::album() const -> const std::optional<std::pmr::string>& { auto TrackTags::album() const -> const std::optional<std::pmr::string>& {
@ -281,41 +291,7 @@ auto TrackTags::genres() const -> std::span<const std::pmr::string> {
} }
auto TrackTags::genres(const std::string_view s) -> void { auto TrackTags::genres(const std::string_view s) -> void {
genres_.clear(); parseDelimitedTags(s, kGenreDelimiters, genres_);
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);
}
}
} }
/* /*

Loading…
Cancel
Save