Skip to content

Commit

Permalink
Add find_by_name() utility function
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
joto committed Nov 10, 2022
1 parent 66a8002 commit 2a32f46
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 18 deletions.
21 changes: 8 additions & 13 deletions src/flex-table-column.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "flex-table-column.hpp"
#include "format.hpp"
#include "util.hpp"

#include <algorithm>
#include <array>
Expand All @@ -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<column_type_lookup, 26> const column_types = {
Expand Down Expand Up @@ -51,22 +54,14 @@ static std::array<column_type_lookup, 26> 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)
Expand Down
6 changes: 1 addition & 5 deletions src/output-flex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)};
}
Expand Down
26 changes: 26 additions & 0 deletions src/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "format.hpp"
#include "osmtypes.hpp"

#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
Expand Down Expand Up @@ -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 <typename CONTAINER>
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
30 changes: 30 additions & 0 deletions tests/test-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

#include <cstring>
#include <limits>
#include <string>
#include <vector>

TEST_CASE("integer_to_buffer 1", "[NoDB]")
{
Expand Down Expand Up @@ -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<test_class> 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);
}

0 comments on commit 2a32f46

Please sign in to comment.