Skip to content

Commit b15ac65

Browse files
authored
refactor: use std::from_chars instead of stoi/stoll/stod (#556)
1 parent 8a14f9c commit b15ac65

15 files changed

+63
-51
lines changed

src/iceberg/avro/avro_schema_util.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
*/
1919

2020
#include <format>
21-
#include <mutex>
2221
#include <sstream>
2322
#include <string_view>
2423

@@ -31,13 +30,12 @@
3130
#include <avro/ValidSchema.hh>
3231

3332
#include "iceberg/avro/avro_constants.h"
34-
#include "iceberg/avro/avro_register.h"
3533
#include "iceberg/avro/avro_schema_util_internal.h"
3634
#include "iceberg/metadata_columns.h"
3735
#include "iceberg/name_mapping.h"
3836
#include "iceberg/schema.h"
3937
#include "iceberg/schema_util_internal.h"
40-
#include "iceberg/util/formatter.h"
38+
#include "iceberg/util/formatter.h" // IWYU pragma: keep
4139
#include "iceberg/util/macros.h"
4240
#include "iceberg/util/string_util.h"
4341
#include "iceberg/util/visit_type.h"
@@ -471,7 +469,7 @@ Result<int32_t> GetId(const ::avro::NodePtr& node, const std::string& attr_name,
471469
return InvalidSchema("Missing avro attribute: {}", attr_name);
472470
}
473471

474-
return StringUtils::ParseInt<int32_t>(id_str.value());
472+
return StringUtils::ParseNumber<int32_t>(id_str.value());
475473
}
476474

477475
Result<int32_t> GetElementId(const ::avro::NodePtr& node) {
@@ -729,7 +727,8 @@ Result<FieldProjection> ProjectMap(const MapType& map_type,
729727
const auto& expected_value_field = map_type.value();
730728

731729
FieldProjection result;
732-
int32_t avro_key_id, avro_value_id;
730+
int32_t avro_key_id;
731+
int32_t avro_value_id;
733732
::avro::NodePtr map_node;
734733

735734
if (avro_node->type() == ::avro::AVRO_MAP) {

src/iceberg/avro/avro_writer.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Result<std::optional<int32_t>> ParseCodecLevel(const WriterProperties& propertie
7676
if (level_str.empty()) {
7777
return std::nullopt;
7878
}
79-
ICEBERG_ASSIGN_OR_RAISE(auto level, StringUtils::ParseInt<int32_t>(level_str));
79+
ICEBERG_ASSIGN_OR_RAISE(auto level, StringUtils::ParseNumber<int32_t>(level_str));
8080
return level;
8181
}
8282

src/iceberg/json_serde.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "iceberg/util/formatter.h" // IWYU pragma: keep
4848
#include "iceberg/util/json_util_internal.h"
4949
#include "iceberg/util/macros.h"
50+
#include "iceberg/util/string_util.h"
5051
#include "iceberg/util/timepoint.h"
5152

5253
namespace iceberg {
@@ -497,15 +498,20 @@ Result<std::unique_ptr<Type>> TypeFromJson(const nlohmann::json& json) {
497498
std::regex fixed_regex(R"(fixed\[\s*(\d+)\s*\])");
498499
std::smatch match;
499500
if (std::regex_match(type_str, match, fixed_regex)) {
500-
return std::make_unique<FixedType>(std::stoi(match[1].str()));
501+
ICEBERG_ASSIGN_OR_RAISE(auto length,
502+
StringUtils::ParseNumber<int32_t>(match[1].str()));
503+
return std::make_unique<FixedType>(length);
501504
}
502505
return JsonParseError("Invalid fixed type: {}", type_str);
503506
} else if (type_str.starts_with("decimal")) {
504507
std::regex decimal_regex(R"(decimal\(\s*(\d+)\s*,\s*(\d+)\s*\))");
505508
std::smatch match;
506509
if (std::regex_match(type_str, match, decimal_regex)) {
507-
return std::make_unique<DecimalType>(std::stoi(match[1].str()),
508-
std::stoi(match[2].str()));
510+
ICEBERG_ASSIGN_OR_RAISE(auto precision,
511+
StringUtils::ParseNumber<int32_t>(match[1].str()));
512+
ICEBERG_ASSIGN_OR_RAISE(auto scale,
513+
StringUtils::ParseNumber<int32_t>(match[2].str()));
514+
return std::make_unique<DecimalType>(precision, scale);
509515
}
510516
return JsonParseError("Invalid decimal type: {}", type_str);
511517
} else {

src/iceberg/metrics_config.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
#include "iceberg/metrics_config.h"
2121

22-
#include <charconv>
2322
#include <string>
2423
#include <unordered_map>
2524

@@ -29,6 +28,8 @@
2928
#include "iceberg/table.h"
3029
#include "iceberg/table_properties.h"
3130
#include "iceberg/util/checked_cast.h"
31+
#include "iceberg/util/macros.h"
32+
#include "iceberg/util/string_util.h"
3233
#include "iceberg/util/type_util.h"
3334

3435
namespace iceberg {
@@ -84,12 +85,12 @@ Result<MetricsMode> MetricsMode::FromString(std::string_view mode) {
8485
}
8586

8687
if (StringUtils::StartsWithIgnoreCase(mode, kTruncatePrefix) && mode.ends_with(")")) {
87-
int32_t length;
88-
auto [ptr, ec] = std::from_chars(mode.data() + 9 /* "truncate(" length */,
89-
mode.data() + mode.size() - 1, length);
90-
if (ec != std::errc{}) {
88+
auto res = StringUtils::ParseNumber<int32_t>(
89+
mode.substr(9 /* "truncate(" length */, mode.size() - 10));
90+
if (!res.has_value()) {
9191
return InvalidArgument("Invalid truncate mode: {}", mode);
9292
}
93+
int32_t length = res.value();
9394
if (length == kDefaultTruncateLength) {
9495
return kDefaultMetricsMode;
9596
}

src/iceberg/parquet/parquet_schema_util.cc

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
#include <charconv>
21-
2220
#include <arrow/extension_type.h>
2321
#include <arrow/type.h>
2422
#include <arrow/type_fwd.h>
@@ -32,8 +30,9 @@
3230
#include "iceberg/result.h"
3331
#include "iceberg/schema_util_internal.h"
3432
#include "iceberg/util/checked_cast.h"
35-
#include "iceberg/util/formatter.h"
33+
#include "iceberg/util/formatter.h" // IWYU pragma: keep
3634
#include "iceberg/util/macros.h"
35+
#include "iceberg/util/string_util.h"
3736

3837
namespace iceberg::parquet {
3938

@@ -49,13 +48,11 @@ std::optional<int32_t> FieldIdFromMetadata(
4948
return std::nullopt;
5049
}
5150
std::string field_id_str = metadata->value(key);
52-
int32_t field_id = -1;
53-
auto [_, ec] = std::from_chars(field_id_str.data(),
54-
field_id_str.data() + field_id_str.size(), field_id);
55-
if (ec != std::errc() || field_id < 0) {
51+
auto res = StringUtils::ParseNumber<int32_t>(field_id_str);
52+
if (!res.has_value() || res.value() < 0) {
5653
return std::nullopt;
5754
}
58-
return field_id;
55+
return res.value();
5956
}
6057

6158
std::optional<int32_t> GetFieldId(const ::parquet::arrow::SchemaField& parquet_field) {

src/iceberg/parquet/parquet_writer.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Result<std::optional<int32_t>> ParseCodecLevel(const WriterProperties& propertie
7070
if (level_str.empty()) {
7171
return std::nullopt;
7272
}
73-
ICEBERG_ASSIGN_OR_RAISE(auto level, StringUtils::ParseInt<int32_t>(level_str));
73+
ICEBERG_ASSIGN_OR_RAISE(auto level, StringUtils::ParseNumber<int32_t>(level_str));
7474
return level;
7575
}
7676

src/iceberg/result.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ using Status = Result<void>;
8888
return std::unexpected<Error>( \
8989
{ErrorKind::k##name, std::format(fmt, std::forward<Args>(args)...)}); \
9090
} \
91-
inline auto name(const std::string& message) -> std::unexpected<Error> { \
92-
return std::unexpected<Error>({ErrorKind::k##name, message}); \
91+
inline auto name(std::string message) -> std::unexpected<Error> { \
92+
return std::unexpected<Error>({ErrorKind::k##name, std::move(message)}); \
9393
}
9494

9595
DEFINE_ERROR_FUNCTION(AlreadyExists)

src/iceberg/snapshot.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Result<std::optional<int64_t>> Snapshot::FirstRowId() const {
167167
return std::nullopt;
168168
}
169169

170-
return StringUtils::ParseInt<int64_t>(it->second);
170+
return StringUtils::ParseNumber<int64_t>(it->second);
171171
}
172172

173173
Result<std::optional<int64_t>> Snapshot::AddedRows() const {
@@ -176,7 +176,7 @@ Result<std::optional<int64_t>> Snapshot::AddedRows() const {
176176
return std::nullopt;
177177
}
178178

179-
return StringUtils::ParseInt<int64_t>(it->second);
179+
return StringUtils::ParseNumber<int64_t>(it->second);
180180
}
181181

182182
bool Snapshot::Equals(const Snapshot& other) const {

src/iceberg/test/update_properties_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ TEST_F(UpdatePropertiesTest, UpgradeFormatVersionInvalidString) {
107107

108108
auto result = update->Apply();
109109
EXPECT_THAT(result, IsError(ErrorKind::kInvalidArgument));
110-
EXPECT_THAT(result, HasErrorMessage("Failed to parse integer from string"));
110+
EXPECT_THAT(result, HasErrorMessage("invalid argument"));
111111
}
112112

113113
TEST_F(UpdatePropertiesTest, UpgradeFormatVersionOutOfRange) {

src/iceberg/transform.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "iceberg/util/checked_cast.h"
3232
#include "iceberg/util/macros.h"
3333
#include "iceberg/util/projection_util_internal.h"
34+
#include "iceberg/util/string_util.h"
3435
#include "iceberg/util/transform_util.h"
3536

3637
namespace iceberg {
@@ -514,7 +515,8 @@ Result<std::shared_ptr<Transform>> TransformFromString(std::string_view transfor
514515
std::smatch match;
515516
if (std::regex_match(str, match, param_regex)) {
516517
const std::string type_str = match[1];
517-
const int32_t param = std::stoi(match[2]);
518+
ICEBERG_ASSIGN_OR_RAISE(const auto param,
519+
StringUtils::ParseNumber<int32_t>(match[2].str()));
518520

519521
if (type_str == kBucketName) {
520522
return Transform::Bucket(param);

0 commit comments

Comments
 (0)