Skip to content

Commit 8d1ddc5

Browse files
committed
perf: improve ends_in_a_number by 25%
1 parent dcac59b commit 8d1ddc5

File tree

2 files changed

+58
-11
lines changed

2 files changed

+58
-11
lines changed

include/ada/checkers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace ada::checkers {
1010
bool ends_in_a_number(std::string_view input) noexcept;
1111
bool is_windows_drive_letter(std::string_view input) noexcept;
1212
bool is_normalized_windows_drive_letter(std::string_view input) noexcept;
13+
ada_really_inline constexpr bool is_ipv4_number_valid(const std::string_view input) noexcept;
1314

1415
} // namespace ada::checkers
1516

src/checkers.cpp

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,55 @@ namespace ada::checkers {
77

88
// TODO: Refactor this to not use `std::vector` but use pointer arithmetic for performance.
99
bool ends_in_a_number(const std::string_view input) noexcept {
10-
// Let parts be the result of strictly splitting input on U+002E (.).
11-
std::vector<std::string> parts = ada::helpers::split_string_view(input, '.', false);
12-
13-
if (parts.empty()) {
10+
if (input.empty()) {
1411
return false;
1512
}
1613

14+
size_t parts_count = std::count(input.begin(), input.end(), '.');
15+
16+
if (parts_count > 0) { parts_count++; }
17+
18+
static const std::string delimiter = ".";
19+
std::string_view::iterator pointer_start = input.begin();
20+
std::string_view::iterator pointer_end = input.end();
21+
1722
// If the last item in parts is the empty string, then:
18-
if (parts.back().empty()) {
23+
if (input.back() == '.') {
1924
// If parts’s size is 1, then return false.
20-
if (parts.size() == 1) {
25+
if (parts_count == 1) {
2126
return false;
2227
}
2328

2429
// Remove the last item from parts.
25-
parts.pop_back();
30+
pointer_end--;
31+
parts_count--;
32+
}
33+
34+
if (std::distance(pointer_start, pointer_end) == 0) {
35+
return false;
2636
}
2737

28-
// Let last be the last item in parts.
29-
std::string_view last = parts.back();
38+
if (parts_count > 1) {
39+
pointer_start = std::find_end(pointer_start, pointer_end, delimiter.begin(), delimiter.end());
40+
41+
if (pointer_start == pointer_end) {
42+
return false;
43+
}
44+
45+
pointer_start++;
46+
}
47+
48+
if (std::distance(pointer_start, pointer_end) == 0) {
49+
return false;
50+
}
3051

3152
// If last is non-empty and contains only ASCII digits, then return true.
32-
if (!last.empty() && std::all_of(last.begin(), last.end(), ::isdigit)) {
53+
if (std::all_of(pointer_start, pointer_end, ::isdigit)) {
3354
return true;
3455
}
3556

3657
// If parsing last as an IPv4 number does not return failure, then return true.
37-
return ada::parser::parse_ipv4_number(last).has_value();
58+
return is_ipv4_number_valid(std::string(pointer_start, pointer_end));
3859
}
3960

4061
// A Windows drive letter is two code points, of which the first is an ASCII alpha
@@ -48,5 +69,30 @@ namespace ada::checkers {
4869
return is_windows_drive_letter(input) && input[1] == ':';
4970
}
5071

72+
// This function assumes the input is not empty.
73+
ada_really_inline constexpr bool is_ipv4_number_valid(const std::string_view input) noexcept {
74+
// The first two code points are either "0X" or "0x", then:
75+
if (input.length() >= 2 && input[0] == '0' && (input[1] == 'X' || input[1] == 'x')) {
76+
if (input.length() == 2) {
77+
return true;
78+
}
79+
80+
// Remove the first two code points from input.
81+
// If input contains a code point that is not a radix-R digit, then return failure.
82+
return input.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string_view::npos;
83+
}
84+
// Otherwise, if the first code point is U+0030 (0), then:
85+
else if (input[0] == '0') {
86+
if (input.length() == 1) {
87+
return true;
88+
}
89+
90+
// Remove the first code point from input.
91+
// If input contains a code point that is not a radix-R digit, then return failure.
92+
return input.find_first_not_of("01234567", 1) == std::string_view::npos;
93+
}
94+
95+
return std::all_of(input.begin(), input.end(), ::isdigit);
96+
}
5197

5298
} // namespace ada::checkers

0 commit comments

Comments
 (0)