diff --git a/src/format.h b/src/format.h index 17cf23e0..bfe9534a 100644 --- a/src/format.h +++ b/src/format.h @@ -60,6 +60,10 @@ private: unsigned m_delimiter; }; +template using SongTagMap = std::vector< + std::pair > +>; + enum class Result { Empty, Missing, Ok }; template diff --git a/src/format_impl.h b/src/format_impl.h index 1f138b79..0154310d 100644 --- a/src/format_impl.h +++ b/src/format_impl.h @@ -130,7 +130,7 @@ struct Printer: boost::static_visitor else tags = wideShorten(tags, st.delimiter()); } - output(tags); + output(tags, &st); return Result::Ok; } else @@ -177,10 +177,11 @@ private: // generic version for streams (buffers, menus) template struct output_ { - static void exec(OutputStreamT &os, const ValueT &value) { + static void exec(OutputStreamT &os, const ValueT &value, const SongTag *) { os << value; } }; + // specialization for strings (input/output) template struct output_, std::basic_string> { @@ -191,7 +192,7 @@ private: static typename std::enable_if< std::is_same::value, void - >::type exec(SomeString &result, const OtherString &s) { + >::type exec(SomeString &result, const OtherString &s, const SongTag *) { result += s; } }; @@ -199,20 +200,43 @@ private: // properties. if this code is reached, throw an exception. template struct output_> { - static void exec(std::basic_string &, const ValueT &) { + static void exec(std::basic_string &, const ValueT &, const SongTag *) { throw std::logic_error("non-string property can't be appended to the string"); } }; + // Specialization for SongTagMap. + template + struct output_, SongTagMap > { + // Compile only if string types are the same. + static typename std::enable_if< + std::is_same::value, + void + >::type exec(SongTagMap &acc, + const std::basic_string &s, const SongTag *st) { + if (st != nullptr) { + acc.emplace_back(*st, s); + } + } + }; + // When extracting tags from a song all the other properties should + // be ignored. If that's not the case, throw an exception. + template + struct output_ > { + static void exec(SongTagMap &, const ValueT &, const SongTag *) { + throw std::logic_error("Non-string property can't be inserted into the SongTagMap"); + } + }; + template - void output(const ValueT &value) const + void output(const ValueT &value, const SongTag *st = nullptr) const { if (!m_no_output) { if (m_output_switched && m_second_os != nullptr) - output_::exec(*m_second_os, value); + output_::exec(*m_second_os, value, st); else - output_::exec(m_output, value); + output_::exec(m_output, value, st); } } @@ -258,6 +282,15 @@ std::basic_string stringify(const AST &ast, const MPD::Song *song) return result; } +template +SongTagMap extractTags(const AST &ast, const MPD::Song &song) +{ + SongTagMap result; + Printer > printer(result, &song, &result, Flags::Tag); + visit(printer, ast); + return result; +} + } #endif // NCMPCPP_HAVE_FORMAT__IMPL_H