std::string_view 的使用

This commit is contained in:
2026-06-29 09:40:55 +08:00
parent cd446b7ca8
commit 8daf67aa5d
52 changed files with 1420 additions and 1367 deletions
@@ -14,6 +14,7 @@
#include <stdexcept>
#include <system_error>
#include <utility>
#include <string_view>
namespace External_Database_Utils {
namespace {
@@ -27,15 +28,15 @@ const std::vector<std::string> kTar1090Columns = {
"type_name", "year", "operator_info"};
const std::vector<std::string> kTar1090PrimaryKey = {"icao24"};
std::pair<std::string, std::string> split_url(const std::string &url) {
std::pair<std::string, std::string> split_url(std::string_view url) {
const auto scheme_end = url.find("://");
if (scheme_end == std::string::npos) {
throw std::runtime_error("Invalid download URL: " + url);
throw std::runtime_error("Invalid download URL: " + std::string(url));
}
const auto path_begin = url.find('/', scheme_end + 3);
if (path_begin == std::string::npos)
return {url, "/"};
return {url.substr(0, path_begin), url.substr(path_begin)};
return {std::string(url), "/"};
return {std::string(url.substr(0, path_begin)), std::string(url.substr(path_begin))};
}
void replace_file(const std::filesystem::path &temp_file,
@@ -51,7 +52,7 @@ void replace_file(const std::filesystem::path &temp_file,
}
std::string
create_csv_table_sql(const std::string &table_name,
create_csv_table_sql(std::string_view table_name,
const std::vector<std::string> &columns,
const std::vector<std::string> &primary_key_columns) {
std::ostringstream sql;
@@ -133,7 +134,7 @@ private:
class Tar1090_Aircraft_Resource final : public External_Resources {
public:
Tar1090_Aircraft_Resource(std::string name, std::string description,
Tar1090_Aircraft_Resource(std::string_view name, std::string_view description,
const std::uint64_t update_interval_seconds)
: External_Resources(std::move(name), "aircraft.csv", kTar1090Url,
std::move(description), update_interval_seconds) {}
@@ -205,7 +206,7 @@ protected:
} // namespace
std::string quote_identifier(const std::string &value) {
std::string quote_identifier(std::string_view value) {
std::string result = "\"";
for (const char ch : value) {
result += ch;
@@ -216,33 +217,35 @@ std::string quote_identifier(const std::string &value) {
return result;
}
std::string normalize_key(std::string value) {
std::string normalize_key(std::string_view value) {
std::string result(value);
const auto is_space = [](unsigned char ch) { return std::isspace(ch) != 0; };
value.erase(value.begin(),
std::find_if(value.begin(), value.end(),
result.erase(result.begin(),
std::find_if(result.begin(), result.end(),
[&](char ch) { return !is_space(ch); }));
value.erase(std::find_if(value.rbegin(), value.rend(),
result.erase(std::find_if(result.rbegin(), result.rend(),
[&](char ch) { return !is_space(ch); })
.base(),
value.end());
.base(),
result.end());
std::transform(
value.begin(), value.end(), value.begin(),
result.begin(), result.end(), result.begin(),
[](unsigned char ch) { return static_cast<char>(std::toupper(ch)); });
return value;
return result;
}
std::optional<std::string> normalize_field(std::string value) {
std::optional<std::string> normalize_field(std::string_view value) {
std::string result(value);
const auto is_space = [](unsigned char ch) { return std::isspace(ch) != 0; };
value.erase(value.begin(),
std::find_if(value.begin(), value.end(),
result.erase(result.begin(),
std::find_if(result.begin(), result.end(),
[&](char ch) { return !is_space(ch); }));
value.erase(std::find_if(value.rbegin(), value.rend(),
result.erase(std::find_if(result.rbegin(), result.rend(),
[&](char ch) { return !is_space(ch); })
.base(),
value.end());
if (value.empty())
.base(),
result.end());
if (result.empty())
return std::nullopt;
return value;
return result;
}
void bind_optional(SQLite::Statement &statement, const int index,
@@ -295,7 +298,7 @@ bool read_csv_row(std::istream &input, std::vector<std::string> &fields,
}
std::string
make_upsert_sql(const std::string &table_name,
make_upsert_sql(std::string_view table_name,
const std::vector<std::string> &columns,
const std::vector<std::string> &primary_key_columns) {
std::ostringstream sql;
@@ -335,12 +338,13 @@ make_upsert_sql(const std::string &table_name,
return sql.str();
}
void download_to_file(std::string url,
void download_to_file(std::string_view url,
const std::filesystem::path &target_file) {
std::filesystem::create_directories(target_file.parent_path());
constexpr int kMaxRedirects = 5;
auto current_url = std::string(url);
for (int redirect = 0; redirect <= kMaxRedirects; ++redirect) {
const auto [origin, path] = split_url(url);
const auto [origin, path] = split_url(current_url);
auto client = drogon::HttpClient::newHttpClient(origin);
auto request = drogon::HttpRequest::newHttpRequest();
request->setMethod(drogon::Get);
@@ -348,19 +352,19 @@ void download_to_file(std::string url,
request->addHeader("User-Agent", "ECAP_Server external database updater");
const auto [result, response] = client->sendRequest(request, 600.0);
if (result != drogon::ReqResult::Ok || !response) {
throw std::runtime_error("Download failed: " + url);
throw std::runtime_error("Download failed: " + current_url);
}
const int status = static_cast<int>(response->getStatusCode());
if (status >= 300 && status < 400) {
const auto location = response->getHeader("location");
if (location.empty())
throw std::runtime_error("Redirect has no location: " + url);
url = location.front() == '/' ? origin + location : location;
throw std::runtime_error("Redirect has no location: " + current_url);
current_url = location.front() == '/' ? origin + location : location;
continue;
}
if (status != 200) {
throw std::runtime_error("Download returned HTTP " +
std::to_string(status) + ": " + url);
std::to_string(status) + ": " + current_url);
}
const auto temp_file = target_file.string() + ".tmp";
std::ofstream output(temp_file, std::ios::binary | std::ios::trunc);
@@ -374,7 +378,7 @@ void download_to_file(std::string url,
replace_file(temp_file, target_file);
return;
}
throw std::runtime_error("Too many redirects while downloading: " + url);
throw std::runtime_error("Too many redirects while downloading: " + current_url);
}
void decompress_gzip(const std::filesystem::path &gzip_file,
@@ -404,7 +408,7 @@ void decompress_gzip(const std::filesystem::path &gzip_file,
std::size_t import_header_csv(
SQLite::Database &db, const std::filesystem::path &source_file,
const std::string &table_name, const std::vector<std::string> &columns,
std::string_view table_name, const std::vector<std::string> &columns,
const std::vector<std::string> &primary_key_columns, const char delimiter) {
std::ifstream input(source_file, std::ios::binary);
if (!input)
@@ -478,7 +482,7 @@ make_schema_only_resource(Schema_Only_Resource_Config config) {
}
std::unique_ptr<External_Resources>
make_tar1090_aircraft_resource(std::string name, std::string description,
make_tar1090_aircraft_resource(std::string_view name, std::string_view description,
const std::uint64_t update_interval_seconds) {
return std::make_unique<Tar1090_Aircraft_Resource>(
std::move(name), std::move(description), update_interval_seconds);