diff --git a/src/tag/GenParseName.cxx b/src/tag/GenParseName.cxx new file mode 100644 index 000000000..9868d2e2f --- /dev/null +++ b/src/tag/GenParseName.cxx @@ -0,0 +1,87 @@ +/* + * Copyright 2003-2020 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "Type.h" + +#include +#include + +#include + +/* + + This program generates an optimized parser for tag names, by doign + switch() on the first character. This reduces the number of + strcmp() calls. + + */ + +int +main(int argc, char **argv) +{ + if (argc != 2) + return EXIT_FAILURE; + + FILE *out = fopen(argv[1], "w"); + + std::map names; + for (unsigned i = 0; i < unsigned(TAG_NUM_OF_ITEM_TYPES); ++i) + names[tag_item_names[i]] = TagType(i); + + fprintf(out, + "#include \"ParseName.hxx\"\n" + "\n" + "#include \n" + "#include \n" + "\n" + "TagType\n" + "tag_name_parse(const char *name) noexcept\n" + "{\n" + " assert(name != nullptr);\n" + "\n" + " switch (*name) {\n"); + + char first = 0; + + for (const auto &i : names) { + const std::string_view name = i.first; + const TagType tag = i.second; + + if (name.front() != first) { + if (first != 0) + fprintf(out, " break;\n\n"); + first = name.front(); + fprintf(out, " case '%c':\n", first); + } + + fprintf(out, + " if (strcmp(name + 1, \"%.*s\") == 0) return TagType(%u);\n", + int(name.size() - 1), name.data() + 1, unsigned(tag)); + } + + fprintf(out, " break;\n\n"); + + fprintf(out, + " }\n" + "\n" + " return TAG_NUM_OF_ITEM_TYPES;\n" + "}\n"); + + return EXIT_SUCCESS; +} diff --git a/src/tag/ParseName.cxx b/src/tag/ParseName.cxx index b9d6182aa..9ec6a97bd 100644 --- a/src/tag/ParseName.cxx +++ b/src/tag/ParseName.cxx @@ -25,21 +25,6 @@ #include -TagType -tag_name_parse(const char *name) noexcept -{ - assert(name != nullptr); - - for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) { - assert(tag_item_names[i] != nullptr); - - if (strcmp(name, tag_item_names[i]) == 0) - return (TagType)i; - } - - return TAG_NUM_OF_ITEM_TYPES; -} - TagType tag_name_parse(StringView name) noexcept { diff --git a/src/tag/meson.build b/src/tag/meson.build index 13e722f0b..064eada18 100644 --- a/src/tag/meson.build +++ b/src/tag/meson.build @@ -1,3 +1,18 @@ +generate_parse_name = executable( + 'GenParseName', + 'GenParseName.cxx', + 'Names.c', + native: true, +) + +parse_name_cxx = custom_target( + 'RunGenParseName', + output: ['ParseName2.cxx'], + command : [ + generate_parse_name, '@OUTPUT@', + ], +) + tag_sources = [ 'Tag.cxx', 'Builder.cxx', @@ -5,6 +20,7 @@ tag_sources = [ 'Settings.cxx', 'Config.cxx', 'ParseName.cxx', + parse_name_cxx, 'Names.c', 'FixString.cxx', 'Pool.cxx',