From 2a32f46753e314714567a8aacba863206a5a1c0c Mon Sep 17 00:00:00 2001 From: Jochen Topf Date: Sat, 5 Nov 2022 11:45:21 +0100 Subject: [PATCH] Add find_by_name() utility function This finds an item by name in some kind of container. The only requirement on the item is that it has a `name()` method. We will need this function in more places in the future, so makes sense to factor this out. --- src/flex-table-column.cpp | 21 ++++++++------------- src/output-flex.cpp | 6 +----- src/util.hpp | 26 ++++++++++++++++++++++++++ tests/test-util.cpp | 30 ++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/flex-table-column.cpp b/src/flex-table-column.cpp index ae9bd57f1..570bf9cef 100644 --- a/src/flex-table-column.cpp +++ b/src/flex-table-column.cpp @@ -9,6 +9,7 @@ #include "flex-table-column.hpp" #include "format.hpp" +#include "util.hpp" #include #include @@ -19,8 +20,10 @@ struct column_type_lookup { - char const *name; + char const *m_name; table_column_type type; + + char const *name() const noexcept { return m_name; } }; static std::array const column_types = { @@ -51,22 +54,14 @@ static std::array const column_types = { {"id_type", table_column_type::id_type}, {"id_num", table_column_type::id_num}}}; -static table_column_type -get_column_type_from_string(std::string const &type) +static table_column_type get_column_type_from_string(std::string const &type) { - // Because it doesn't work with MSVC: - // NOLINTNEXTLINE(llvm-qualified-auto,readability-qualified-auto) - auto const it = - std::find_if(std::begin(column_types), std::end(column_types), - [&type](column_type_lookup name_type) { - return type == name_type.name; - }); - - if (it == std::end(column_types)) { + auto const *column_type = util::find_by_name(column_types, type); + if (!column_type) { throw std::runtime_error{"Unknown column type '{}'."_format(type)}; } - return it->type; + return column_type->type; } static std::string lowercase(std::string const &str) diff --git a/src/output-flex.cpp b/src/output-flex.cpp index 8db2f8d7a..b8a012abf 100644 --- a/src/output-flex.cpp +++ b/src/output-flex.cpp @@ -1006,11 +1006,7 @@ flex_table_t &output_flex_t::create_flex_table() check_identifier(table_name, "table names"); - auto const it = std::find_if(m_tables->cbegin(), m_tables->cend(), - [&table_name](flex_table_t const &table) { - return table.name() == table_name; - }); - if (it != m_tables->cend()) { + if (util::find_by_name(*m_tables, table_name)) { throw std::runtime_error{ "Table with name '{}' already exists."_format(table_name)}; } diff --git a/src/util.hpp b/src/util.hpp index 2dbe5bee0..bca737f3e 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -13,6 +13,7 @@ #include "format.hpp" #include "osmtypes.hpp" +#include #include #include #include @@ -129,6 +130,31 @@ std::string human_readable_duration(std::chrono::milliseconds ms); std::string get_password(); +/** + * Helper function that finds items in a container by name. The items must have + * a name() member function (with a result comparable to std::string) for this + * to work. + * + * \tparam CONTAINER Any kind of container type (must support std::begin/end). + * \param container The container to look through. + * \param name The name to look for. + * \returns Pointer to item, nullptr if not found. + */ +template +auto find_by_name(CONTAINER &container, std::string const &name) + -> decltype(&*std::begin(container)) +{ + auto const it = + std::find_if(std::begin(container), std::end(container), + [&name](auto const &item) { return item.name() == name; }); + + if (it == std::end(container)) { + return nullptr; + } + + return &*it; +} + } // namespace util #endif // OSM2PGSQL_UTIL_HPP diff --git a/tests/test-util.cpp b/tests/test-util.cpp index e78531f13..2af233aba 100644 --- a/tests/test-util.cpp +++ b/tests/test-util.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include TEST_CASE("integer_to_buffer 1", "[NoDB]") { @@ -82,3 +84,31 @@ TEST_CASE("human readable time durations", "[NoDB]") REQUIRE(util::human_readable_duration(152592) == "152592s (42h 23m 12s)"); } +TEST_CASE("find_by_name()", "[NoDB]") +{ + class test_class + { + public: + explicit test_class(std::string n) : m_name(std::move(n)) {} + std::string name() const noexcept { return m_name; } + + private: + std::string m_name; + }; + + std::vector t; + + REQUIRE(util::find_by_name(t, "") == nullptr); + REQUIRE(util::find_by_name(t, "foo") == nullptr); + REQUIRE(util::find_by_name(t, "nothing") == nullptr); + + t.emplace_back("foo"); + t.emplace_back("bar"); + t.emplace_back("baz"); + + REQUIRE(util::find_by_name(t, "") == nullptr); + REQUIRE(util::find_by_name(t, "foo") == &t[0]); + REQUIRE(util::find_by_name(t, "bar") == &t[1]); + REQUIRE(util::find_by_name(t, "baz") == &t[2]); + REQUIRE(util::find_by_name(t, "nothing") == nullptr); +}