Skip to content

Commit 91de476

Browse files
Reddimusclaude
andcommitted
refactor: replace std::ostringstream with std::format / std::format_to
4 non-SQL sites migrated: - format_date in date_range.cpp → std::format("{:04d}-{:02d}-{:02d}", ...) - CDOClient::build_list_query → std::format_to + back_inserter with a local append() lambda - CDOClient::build_data_query → std::format + per-field std::format_to - DataServiceClient::build_data_query → std::format + per-field std::format_to std::format (C++23 stdlib) eliminates per-call ostringstream heap allocations and virtual stream-buffer dispatch. No behavior change; all 166 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 226f32c commit 91de476

3 files changed

Lines changed: 60 additions & 117 deletions

File tree

src/api/cdo_client.cpp

Lines changed: 37 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
#include "ncei/models/common.hpp"
44

5+
#include <format>
6+
#include <iterator>
57
#include <nlohmann/json.hpp>
6-
#include <sstream>
78
#include <utility>
89

910
namespace ncei {
@@ -56,98 +57,55 @@ Result<HttpResponse> CDOClient::do_get(std::string_view path) {
5657
}
5758

5859
std::string CDOClient::build_list_query(std::string_view base, const CDOListParams& params) {
59-
std::ostringstream oss;
60-
oss << base;
60+
std::string url(base);
61+
url.reserve(url.size() + 256);
62+
std::back_insert_iterator<std::string> out(url);
6163
char sep = '?';
6264

63-
if (params.dataset_id) {
64-
oss << sep << "datasetid=" << *params.dataset_id;
65+
auto append = [&](std::string_view key, const auto& value) {
66+
std::format_to(out, "{}{}={}", sep, key, value);
6567
sep = '&';
66-
}
67-
if (params.location_id) {
68-
oss << sep << "locationid=" << *params.location_id;
69-
sep = '&';
70-
}
71-
if (params.station_id) {
72-
oss << sep << "stationid=" << *params.station_id;
73-
sep = '&';
74-
}
75-
if (params.data_type_id) {
76-
oss << sep << "datatypeid=" << *params.data_type_id;
77-
sep = '&';
78-
}
79-
if (params.data_category_id) {
80-
oss << sep << "datacategoryid=" << *params.data_category_id;
81-
sep = '&';
82-
}
83-
if (params.location_category_id) {
84-
oss << sep << "locationcategoryid=" << *params.location_category_id;
85-
sep = '&';
86-
}
87-
if (params.start_date) {
88-
oss << sep << "startdate=" << *params.start_date;
89-
sep = '&';
90-
}
91-
if (params.end_date) {
92-
oss << sep << "enddate=" << *params.end_date;
93-
sep = '&';
94-
}
95-
if (params.sort_field) {
96-
oss << sep << "sortfield=" << *params.sort_field;
97-
sep = '&';
98-
}
99-
if (params.sort_order) {
100-
oss << sep << "sortorder=" << *params.sort_order;
101-
sep = '&';
102-
}
103-
if (params.limit) {
104-
oss << sep << "limit=" << *params.limit;
105-
sep = '&';
106-
}
107-
if (params.offset) {
108-
oss << sep << "offset=" << *params.offset;
109-
sep = '&';
110-
}
111-
112-
return oss.str();
68+
};
69+
70+
if (params.dataset_id) append("datasetid", *params.dataset_id);
71+
if (params.location_id) append("locationid", *params.location_id);
72+
if (params.station_id) append("stationid", *params.station_id);
73+
if (params.data_type_id) append("datatypeid", *params.data_type_id);
74+
if (params.data_category_id) append("datacategoryid", *params.data_category_id);
75+
if (params.location_category_id) append("locationcategoryid", *params.location_category_id);
76+
if (params.start_date) append("startdate", *params.start_date);
77+
if (params.end_date) append("enddate", *params.end_date);
78+
if (params.sort_field) append("sortfield", *params.sort_field);
79+
if (params.sort_order) append("sortorder", *params.sort_order);
80+
if (params.limit) append("limit", *params.limit);
81+
if (params.offset) append("offset", *params.offset);
82+
83+
return url;
11384
}
11485

11586
std::string CDOClient::build_data_query(const GetDataParams& params) {
116-
std::ostringstream oss;
117-
oss << "/data?datasetid=" << params.dataset_id << "&startdate=" << params.start_date
118-
<< "&enddate=" << params.end_date;
87+
std::string url = std::format("/data?datasetid={}&startdate={}&enddate={}",
88+
params.dataset_id, params.start_date, params.end_date);
89+
std::back_insert_iterator<std::string> out(url);
11990

12091
if (params.data_type_ids) {
12192
for (const std::string& dt : *params.data_type_ids) {
122-
oss << "&datatypeid=" << dt;
93+
std::format_to(out, "&datatypeid={}", dt);
12394
}
12495
}
125-
if (params.location_id) {
126-
oss << "&locationid=" << *params.location_id;
127-
}
128-
if (params.station_id) {
129-
oss << "&stationid=" << *params.station_id;
130-
}
131-
if (params.sort_field) {
132-
oss << "&sortfield=" << *params.sort_field;
133-
}
134-
if (params.sort_order) {
135-
oss << "&sortorder=" << *params.sort_order;
136-
}
137-
if (params.limit) {
138-
oss << "&limit=" << *params.limit;
139-
}
140-
if (params.offset) {
141-
oss << "&offset=" << *params.offset;
142-
}
143-
if (params.units) {
144-
oss << "&units=" << *params.units;
145-
}
96+
if (params.location_id) std::format_to(out, "&locationid={}", *params.location_id);
97+
if (params.station_id) std::format_to(out, "&stationid={}", *params.station_id);
98+
if (params.sort_field) std::format_to(out, "&sortfield={}", *params.sort_field);
99+
if (params.sort_order) std::format_to(out, "&sortorder={}", *params.sort_order);
100+
if (params.limit) std::format_to(out, "&limit={}", *params.limit);
101+
if (params.offset) std::format_to(out, "&offset={}", *params.offset);
102+
if (params.units) std::format_to(out, "&units={}", *params.units);
146103
if (params.include_metadata) {
147-
oss << "&includemetadata=" << (*params.include_metadata ? "true" : "false");
104+
std::format_to(out, "&includemetadata={}",
105+
*params.include_metadata ? "true" : "false");
148106
}
149107

150-
return oss.str();
108+
return url;
151109
}
152110

153111
namespace {

src/api/data_service_client.cpp

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
#include "ncei/models/common.hpp"
44

5+
#include <format>
6+
#include <iterator>
57
#include <nlohmann/json.hpp>
6-
#include <sstream>
78
#include <utility>
89

910
namespace ncei {
@@ -60,59 +61,47 @@ Result<HttpResponse> DataServiceClient::do_get(std::string_view path) {
6061
}
6162

6263
std::string DataServiceClient::build_data_query(const DataRequestParams& params) {
63-
std::ostringstream oss;
64-
oss << "/data/v1?dataset=" << params.dataset;
64+
std::string url = std::format("/data/v1?dataset={}", params.dataset);
65+
url.reserve(url.size() + 256);
66+
std::back_insert_iterator<std::string> out(url);
6567

6668
if (params.start_date) {
67-
oss << "&startDate=" << url_encode_date(*params.start_date);
69+
std::format_to(out, "&startDate={}", url_encode_date(*params.start_date));
6870
}
6971
if (params.end_date) {
70-
oss << "&endDate=" << url_encode_date(*params.end_date);
72+
std::format_to(out, "&endDate={}", url_encode_date(*params.end_date));
7173
}
7274
if (params.stations) {
7375
bool first = true;
7476
for (const std::string& station : *params.stations) {
75-
if (first) {
76-
oss << "&stations=";
77-
first = false;
78-
} else {
79-
oss << ",";
80-
}
81-
oss << station;
77+
std::format_to(out, "{}{}", first ? "&stations=" : ",", station);
78+
first = false;
8279
}
8380
}
8481
if (params.data_types) {
8582
bool first = true;
8683
for (const std::string& dt : *params.data_types) {
87-
if (first) {
88-
oss << "&dataTypes=";
89-
first = false;
90-
} else {
91-
oss << ",";
92-
}
93-
oss << dt;
84+
std::format_to(out, "{}{}", first ? "&dataTypes=" : ",", dt);
85+
first = false;
9486
}
9587
}
96-
if (params.format) {
97-
oss << "&format=" << to_string(*params.format);
98-
}
99-
if (params.units) {
100-
oss << "&units=" << *params.units;
101-
}
102-
if (params.bbox) {
103-
oss << "&boundingBox=" << *params.bbox;
104-
}
88+
if (params.format) std::format_to(out, "&format={}", to_string(*params.format));
89+
if (params.units) std::format_to(out, "&units={}", *params.units);
90+
if (params.bbox) std::format_to(out, "&boundingBox={}", *params.bbox);
10591
if (params.include_attributes) {
106-
oss << "&includeAttributes=" << (*params.include_attributes ? "true" : "false");
92+
std::format_to(out, "&includeAttributes={}",
93+
*params.include_attributes ? "true" : "false");
10794
}
10895
if (params.include_station_name) {
109-
oss << "&includeStationName=" << (*params.include_station_name ? "true" : "false");
96+
std::format_to(out, "&includeStationName={}",
97+
*params.include_station_name ? "true" : "false");
11098
}
11199
if (params.include_station_location) {
112-
oss << "&includeStationLocation=" << (*params.include_station_location ? "true" : "false");
100+
std::format_to(out, "&includeStationLocation={}",
101+
*params.include_station_location ? "true" : "false");
113102
}
114103

115-
return oss.str();
104+
return url;
116105
}
117106

118107
Result<DataPointCollection> DataServiceClient::get_data(const DataRequestParams& params) {

src/core/date_range.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#include "ncei/date_range.hpp"
22

33
#include <chrono>
4-
#include <iomanip>
5-
#include <sstream>
4+
#include <format>
65
#include <stdexcept>
76

87
namespace ncei {
@@ -36,10 +35,7 @@ DateParts parse_date(const std::string& iso_date) {
3635
}
3736

3837
std::string format_date(const DateParts& parts) {
39-
std::ostringstream oss;
40-
oss << std::setfill('0') << std::setw(4) << parts.year << '-' << std::setw(2) << parts.month
41-
<< '-' << std::setw(2) << parts.day;
42-
return oss.str();
38+
return std::format("{:04d}-{:02d}-{:02d}", parts.year, parts.month, parts.day);
4339
}
4440

4541
std::int32_t days_between(const std::string& start, const std::string& end) {

0 commit comments

Comments
 (0)