Skip to content

Commit 5f37ff1

Browse files
committed
Refactor StringUtils as core/string headers
1 parent e21ccbb commit 5f37ff1

File tree

26 files changed

+303
-242
lines changed

26 files changed

+303
-242
lines changed

src/headless/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ static bool run_headless(fs::path const& root, memory::vector<memory::string>& m
376376
*/
377377

378378
int main(int argc, char const* argv[]) {
379-
char const* program_name = StringUtils::get_filename(argc > 0 ? argv[0] : nullptr, "<program>");
379+
char const* program_name = get_filename(argc > 0 ? argv[0] : nullptr, "<program>");
380380
fs::path root;
381381
memory::vector<memory::string> mods;
382382
mods.reserve(argc);
Lines changed: 46 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,12 @@
11
#pragma once
22

3-
#include <algorithm>
4-
#include <cctype>
53
#include <charconv>
6-
#include <cstddef>
4+
#include <climits>
75
#include <cstdint>
8-
#include <cstring>
96
#include <iterator>
10-
#include <string>
117
#include <string_view>
12-
#include <type_traits>
13-
#include <utility>
148

15-
#include <tsl/ordered_map.h>
16-
17-
#include <range/v3/range/conversion.hpp>
18-
#include <range/v3/view/join.hpp>
19-
#include <range/v3/view/transform.hpp>
20-
21-
#include "openvic-simulation/utility/Containers.hpp"
22-
23-
namespace OpenVic::StringUtils {
9+
namespace OpenVic {
2410
template<typename T>
2511
[[nodiscard]] inline constexpr std::from_chars_result from_chars( //
2612
char const* const first, char const* const last, T& raw_value, const int base = 10
@@ -61,29 +47,29 @@ namespace OpenVic::StringUtils {
6147
}
6248
}
6349

64-
using unsigned_t = std::make_unsigned_t<T>;
50+
using unsigned_type = std::make_unsigned_t<T>;
6551

66-
[[maybe_unused]] constexpr unsigned_t uint_max = static_cast<unsigned_t>(-1);
67-
[[maybe_unused]] constexpr unsigned_t int_max = static_cast<unsigned_t>(uint_max >> 1);
68-
[[maybe_unused]] constexpr unsigned_t abs_int_min = static_cast<unsigned_t>(int_max + 1);
52+
[[maybe_unused]] constexpr unsigned_type uint_max = static_cast<unsigned_type>(-1);
53+
[[maybe_unused]] constexpr unsigned_type int_max = static_cast<unsigned_type>(uint_max >> 1);
54+
[[maybe_unused]] constexpr unsigned_type abs_int_min = static_cast<unsigned_type>(int_max + 1);
6955

70-
unsigned_t risky_val;
71-
unsigned_t max_digit;
56+
unsigned_type risky_val;
57+
unsigned_type max_digit;
7258

7359
if constexpr (std::is_signed_v<T>) {
7460
if (minus_sign) {
75-
risky_val = static_cast<unsigned_t>(abs_int_min / base);
76-
max_digit = static_cast<unsigned_t>(abs_int_min % base);
61+
risky_val = static_cast<unsigned_type>(abs_int_min / base);
62+
max_digit = static_cast<unsigned_type>(abs_int_min % base);
7763
} else {
78-
risky_val = static_cast<unsigned_t>(int_max / base);
79-
max_digit = static_cast<unsigned_t>(int_max % base);
64+
risky_val = static_cast<unsigned_type>(int_max / base);
65+
max_digit = static_cast<unsigned_type>(int_max % base);
8066
}
8167
} else {
82-
risky_val = static_cast<unsigned_t>(uint_max / base);
83-
max_digit = static_cast<unsigned_t>(uint_max % base);
68+
risky_val = static_cast<unsigned_type>(uint_max / base);
69+
max_digit = static_cast<unsigned_type>(uint_max % base);
8470
}
8571

86-
unsigned_t value = 0;
72+
unsigned_type value = 0;
8773

8874
bool overflowed = false;
8975

@@ -96,7 +82,7 @@ namespace OpenVic::StringUtils {
9682

9783
if (value < risky_val // never overflows
9884
|| (value == risky_val && digit <= max_digit)) { // overflows for certain digits
99-
value = static_cast<unsigned_t>(value * base + digit);
85+
value = static_cast<unsigned_type>(value * base + digit);
10086
} else { // value > risky_val always overflows
10187
overflowed = true; // keep going, next still needs to be updated, value is now irrelevant
10288
}
@@ -112,7 +98,7 @@ namespace OpenVic::StringUtils {
11298

11399
if constexpr (std::is_signed_v<T>) {
114100
if (minus_sign) {
115-
value = static_cast<unsigned_t>(0 - value);
101+
value = static_cast<unsigned_type>(0 - value);
116102
}
117103
}
118104

@@ -136,9 +122,9 @@ namespace OpenVic::StringUtils {
136122
};
137123
static_assert(std::size(digits) == 36);
138124

139-
using _unsigned = std::make_unsigned_t<T>;
125+
using unsigned_type = std::make_unsigned_t<T>;
140126

141-
_unsigned value = static_cast<_unsigned>(raw_value);
127+
unsigned_type value = static_cast<unsigned_type>(raw_value);
142128

143129
if constexpr (std::is_signed_v<T>) {
144130
if (raw_value < 0) {
@@ -148,26 +134,26 @@ namespace OpenVic::StringUtils {
148134

149135
*first++ = '-';
150136

151-
value = static_cast<_unsigned>(0 - value);
137+
value = static_cast<unsigned_type>(0 - value);
152138
}
153139
}
154140

155-
constexpr std::size_t buffer_size = sizeof(_unsigned) * CHAR_BIT; // enough for base 2
141+
constexpr std::size_t buffer_size = sizeof(unsigned_type) * CHAR_BIT; // enough for base 2
156142
char buffer[buffer_size];
157143
char* const buffer_end = buffer + buffer_size;
158144
char* r_next = buffer_end;
159145

160146
switch (base) {
161147
case 10: { // Derived from _UIntegral_to_buff()
162148
// Performance note: Ryu's digit table should be faster here.
163-
constexpr bool use_chunks = sizeof(_unsigned) > sizeof(size_t);
149+
constexpr bool use_chunks = sizeof(unsigned_type) > sizeof(size_t);
164150

165151
if constexpr (use_chunks) { // For 64-bit numbers on 32-bit platforms, work in chunks to avoid 64-bit
166-
// divisions.
152+
// divisions.
167153
while (value > 0xFFFF'FFFFU) {
168154
// Performance note: Ryu's division workaround would be faster here.
169155
unsigned long chunk = static_cast<unsigned long>(value % 1'000'000'000);
170-
value = static_cast<_unsigned>(value / 1'000'000'000);
156+
value = static_cast<unsigned_type>(value / 1'000'000'000);
171157

172158
for (int _Idx = 0; _Idx != 9; ++_Idx) {
173159
*--r_next = static_cast<char>('0' + chunk % 10);
@@ -176,9 +162,9 @@ namespace OpenVic::StringUtils {
176162
}
177163
}
178164

179-
using Truncated = std::conditional_t<use_chunks, unsigned long, _unsigned>;
165+
using truncated_type = std::conditional_t<use_chunks, unsigned long, unsigned_type>;
180166

181-
Truncated trunc = static_cast<Truncated>(value);
167+
truncated_type trunc = static_cast<truncated_type>(value);
182168

183169
do {
184170
*--r_next = static_cast<char>('0' + trunc % 10);
@@ -225,7 +211,7 @@ namespace OpenVic::StringUtils {
225211
default:
226212
do {
227213
*--r_next = digits[value % base];
228-
value = static_cast<_unsigned>(value / base);
214+
value = static_cast<unsigned_type>(value / base);
229215
} while (value != 0);
230216
break;
231217
}
@@ -250,11 +236,12 @@ namespace OpenVic::StringUtils {
250236
};
251237
//[neargye] constexpr copy chars. P1944 fix this?
252238
trivial_copy(first, r_next, static_cast<size_t>(digits_written));
253-
239+
254240

255241
return { first + digits_written, std::errc {} };
256242
}
257243

244+
258245
/* The constexpr function 'string_to_uint64' will convert a string into a uint64_t integer value.
259246
* The function takes four parameters: the input string (as a pair of pointers marking the start and
260247
* end of the string), the value reference to assign, and the base for numerical conversion.
@@ -263,7 +250,8 @@ namespace OpenVic::StringUtils {
263250
* still starts with "0", otherwise 10. The std::from_chars_result return value is used to report whether
264251
* or not conversion was successful.
265252
*/
266-
[[nodiscard]] inline constexpr std::from_chars_result string_to_uint64(char const* str, char const* const end, uint64_t& value, int base = 10) {
253+
[[nodiscard]] inline constexpr std::from_chars_result
254+
string_to_uint64(char const* str, char const* const end, uint64_t& value, int base = 10) {
267255
// If base is zero, base is determined by the string prefix.
268256
if (base == 0) {
269257
if (str && *str == '0') {
@@ -286,11 +274,15 @@ namespace OpenVic::StringUtils {
286274
return from_chars(str, end, value, base);
287275
}
288276

289-
[[nodiscard]] inline constexpr std::from_chars_result string_to_uint64(char const* const str, size_t length, uint64_t& value, int base = 10) {
277+
[[nodiscard]] inline constexpr std::from_chars_result string_to_uint64( //
278+
char const* const str, size_t length, std::uint64_t& value, int base = 10
279+
) {
290280
return string_to_uint64(str, str + length, value, base);
291281
}
292282

293-
[[nodiscard]] inline constexpr std::from_chars_result string_to_uint64(std::string_view str, uint64_t& value, int base = 10) {
283+
[[nodiscard]] inline constexpr std::from_chars_result string_to_uint64( //
284+
std::string_view str, std::uint64_t& value, int base = 10
285+
) {
294286
return string_to_uint64(str.data(), str.length(), value, base);
295287
}
296288

@@ -302,7 +294,9 @@ namespace OpenVic::StringUtils {
302294
* still starts with "0", otherwise 10. The std::from_chars_result return value is used to report whether
303295
* or not conversion was successful.
304296
*/
305-
[[nodiscard]] inline constexpr std::from_chars_result string_to_int64(char const* str, char const* const end, int64_t& value, int base = 10) {
297+
[[nodiscard]] inline constexpr std::from_chars_result string_to_int64( //
298+
char const* str, char const* const end, std::int64_t& value, int base = 10
299+
) {
306300
// If base is zero, base is determined by the string prefix.
307301
if (base == 0) {
308302
if (str && *str == '0') {
@@ -325,132 +319,15 @@ namespace OpenVic::StringUtils {
325319
return from_chars(str, end, value, base);
326320
}
327321

328-
[[nodiscard]] inline constexpr std::from_chars_result string_to_int64(char const* str, size_t length, int64_t& value, int base = 10) {
322+
[[nodiscard]] inline constexpr std::from_chars_result string_to_int64( //
323+
char const* str, size_t length, std::int64_t& value, int base = 10
324+
) {
329325
return string_to_int64(str, str + length, value, base);
330326
}
331327

332-
[[nodiscard]] inline constexpr std::from_chars_result string_to_int64(std::string_view str, int64_t& value, int base = 10) {
328+
[[nodiscard]] inline constexpr std::from_chars_result string_to_int64( //
329+
std::string_view str, std::int64_t& value, int base = 10
330+
) {
333331
return string_to_int64(str.data(), str.length(), value, base);
334332
}
335-
336-
inline constexpr bool strings_equal_case_insensitive(std::string_view const& lhs, std::string_view const& rhs) {
337-
if (lhs.size() != rhs.size()) {
338-
return false;
339-
}
340-
constexpr auto ichar_equals = [](unsigned char l, unsigned char r) {
341-
return std::tolower(l) == std::tolower(r);
342-
};
343-
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), ichar_equals);
344-
}
345-
346-
inline memory::string string_tolower(std::string_view str) {
347-
memory::string result { str };
348-
std::transform(result.begin(), result.end(), result.begin(),
349-
[](unsigned char c) -> unsigned char { return std::tolower(c); }
350-
);
351-
return result;
352-
}
353-
354-
inline memory::string string_toupper(std::string_view str) {
355-
memory::string result { str };
356-
std::transform(result.begin(), result.end(), result.begin(),
357-
[](unsigned char c) -> unsigned char { return std::toupper(c); }
358-
);
359-
return result;
360-
}
361-
362-
inline constexpr std::string_view bool_to_yes_no(bool b) {
363-
return b ? "yes" : "no";
364-
}
365-
366-
inline constexpr std::string_view get_filename(std::string_view path) {
367-
size_t pos = path.size();
368-
while (pos > 0 && path[pos - 1] != '/' && path[pos - 1] != '\\') {
369-
--pos;
370-
}
371-
path.remove_prefix(pos);
372-
return path;
373-
}
374-
375-
inline constexpr char const* get_filename(char const* filepath, char const* default_path = nullptr) {
376-
const std::string_view filename { get_filename(std::string_view { filepath }) };
377-
if (!filename.empty()) {
378-
return filename.data();
379-
}
380-
return default_path;
381-
}
382-
383-
inline memory::string make_forward_slash_path(std::string_view path) {
384-
memory::string ret { path };
385-
std::replace(ret.begin(), ret.end(), '\\', '/');
386-
for (char& c : ret) {
387-
if (c == '\\') {
388-
c = '/';
389-
}
390-
}
391-
return ret;
392-
}
393-
394-
inline constexpr std::string_view remove_leading_slashes(std::string_view path) {
395-
size_t count = 0;
396-
while (count < path.size() && (path[count] == '/' || path[count] == '\\')) {
397-
++count;
398-
}
399-
path.remove_prefix(count);
400-
return path;
401-
}
402-
403-
template<typename... Args>
404-
requires(std::is_same_v<std::string_view, Args> && ...)
405-
inline memory::string _append_string_views(Args... args) {
406-
memory::string ret;
407-
ret.reserve((args.size() + ...));
408-
(ret.append(args), ...);
409-
return ret;
410-
}
411-
412-
template<typename... Args>
413-
requires(std::is_convertible_v<Args, std::string_view> && ...)
414-
inline memory::string append_string_views(Args... args) {
415-
return _append_string_views(std::string_view { args }...);
416-
}
417-
418-
template<typename T, typename... Args>
419-
static memory::string string_join(tsl::ordered_map<memory::string, T, Args...> const& map, std::string_view delimiter = ", ") {
420-
if (map.empty()) {
421-
return "";
422-
}
423-
424-
static auto transformer = [](std::pair<std::string_view, T> const& pair) -> std::string_view {
425-
return pair.first;
426-
};
427-
return map | ranges::views::transform(transformer) | ranges::views::join(delimiter) | ranges::to<memory::string>();
428-
}
429-
430-
inline constexpr size_t get_extension_pos(std::string_view const& path) {
431-
size_t pos = path.size();
432-
while (pos > 0 && path[--pos] != '.') {}
433-
return pos;
434-
}
435-
436-
inline constexpr std::string_view get_extension(std::string_view path) {
437-
if (!path.empty()) {
438-
const size_t pos = get_extension_pos(path);
439-
if (path[pos] == '.') {
440-
path.remove_prefix(pos);
441-
return path;
442-
}
443-
}
444-
return {};
445-
}
446-
447-
inline constexpr std::string_view remove_extension(std::string_view path) {
448-
if (!path.empty()) {
449-
const size_t pos = get_extension_pos(path);
450-
if (path[pos] == '.') {
451-
path.remove_suffix(path.size() - pos);
452-
}
453-
}
454-
return path;
455-
}
456333
}

0 commit comments

Comments
 (0)