Skip to content

Commit 051dc1c

Browse files
feat(sourcepp): add more string helpers
1 parent 9b989cd commit 051dc1c

File tree

5 files changed

+124
-13
lines changed

5 files changed

+124
-13
lines changed

include/sourcepp/parser/Text.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,41 @@ extern const std::unordered_map<char, char> NO_ESCAPE_SEQUENCES;
2323
*/
2424
[[nodiscard]] bool isNewLine(char c);
2525

26+
/**
27+
* If a string is entirely composed of newline characters.
28+
* @param str The string.
29+
* @return The string is entirely composed of newline characters.
30+
*/
31+
[[nodiscard]] bool isNewLine(std::string_view str);
32+
2633
/**
2734
* If a char is a whitespace character.
2835
* @param c The char.
2936
* @return The char is a whitespace character.
3037
*/
3138
[[nodiscard]] bool isWhitespace(char c);
3239

40+
/**
41+
* If a string is entirely composed of whitespace characters.
42+
* @param str The string.
43+
* @return The string is entirely composed of whitespace characters.
44+
*/
45+
[[nodiscard]] bool isWhitespace(std::string_view str);
46+
3347
/**
3448
* If a char is a numerical character (0-9).
3549
* @param c The char.
3650
* @return The char is a numerical character.
3751
*/
3852
[[nodiscard]] bool isNumber(char c);
3953

54+
/**
55+
* If a string is entirely composed of numerical characters (0-9).
56+
* @param str The string.
57+
* @return The string is entirely composed of numerical characters.
58+
*/
59+
[[nodiscard]] bool isNumber(std::string_view str);
60+
4061
/**
4162
* Eat all whitespace after the current stream position.
4263
* @param stream The BufferStream to modify.

include/sourcepp/string/String.h

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include <charconv>
4+
#include <concepts>
35
#include <string>
46
#include <string_view>
57
#include <vector>
@@ -14,22 +16,38 @@ namespace sourcepp::string {
1416

1517
void ltrim(std::string& s);
1618

19+
[[nodiscard]] std::string_view ltrim(std::string_view s);
20+
1721
void rtrim(std::string& s);
1822

23+
[[nodiscard]] std::string_view rtrim(std::string_view s);
24+
1925
void trim(std::string& s);
2026

21-
void ltrim(std::string& s, std::string_view c);
27+
[[nodiscard]] std::string_view trim(std::string_view s);
28+
29+
void ltrim(std::string& s, std::string_view chars);
30+
31+
[[nodiscard]] std::string_view ltrim(std::string_view s, std::string_view chars);
32+
33+
void rtrim(std::string& s, std::string_view chars);
2234

23-
void rtrim(std::string& s, std::string_view c);
35+
[[nodiscard]] std::string_view rtrim(std::string_view s, std::string_view chars);
2436

25-
void trim(std::string& s, std::string_view c);
37+
void trim(std::string& s, std::string_view chars);
38+
39+
[[nodiscard]] std::string_view trim(std::string_view s, std::string_view chars);
2640

2741
[[nodiscard]] std::vector<std::string> split(std::string_view s, char delim);
2842

2943
void toLower(std::string& input);
3044

45+
[[nodiscard]] std::string toLower(std::string_view input);
46+
3147
void toUpper(std::string& input);
3248

49+
[[nodiscard]] std::string toUpper(std::string_view input);
50+
3351
[[nodiscard]] std::string createRandom(uint16_t length = 32, std::string_view chars = "0123456789_abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ");
3452

3553
[[nodiscard]] std::string generateUUIDv4();
@@ -40,4 +58,18 @@ void normalizeSlashes(std::string& path, bool stripSlashPrefix = false, bool str
4058

4159
void denormalizeSlashes(std::string& path, bool stripSlashPrefix = false, bool stripSlashSuffix = true);
4260

61+
std::from_chars_result toInt(std::string_view number, std::integral auto& out, int base = 10) {
62+
return std::from_chars(number.data(), number.data() + number.size(), out, base);
63+
}
64+
65+
std::from_chars_result toFloat(std::string_view number, std::floating_point auto& out) {
66+
#ifdef __APPLE__
67+
// Piece of shit compiler
68+
out = std::stof(std::string{number});
69+
return {number.data(), {}};
70+
#else
71+
return std::from_chars(number.data(), number.data() + number.size(), out);
72+
#endif
73+
}
74+
4375
} // namespace sourcepp::string

src/fgdpp/fgdpp.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
#include <fgdpp/fgdpp.h>
22

33
#include <algorithm>
4-
#include <charconv>
54
#include <filesystem>
65
#include <initializer_list>
7-
#include <utility>
86

97
#include <BufferStream.h>
108

@@ -88,7 +86,7 @@ void readVersion(BufferStreamReadOnly& stream, BufferStream& backing, int& versi
8886
}
8987
std::string versionString{parser::text::readStringToBuffer(stream, backing, "(", ")", parser::text::NO_ESCAPE_SEQUENCES)};
9088
string::trim(versionString);
91-
version = std::stoi(versionString);
89+
string::toInt(versionString, version);
9290
}
9391

9492
void readMapSize(BufferStreamReadOnly& stream, BufferStream& backing, math::Vec2i& mapSize) {
@@ -106,8 +104,8 @@ void readMapSize(BufferStreamReadOnly& stream, BufferStream& backing, math::Vec2
106104

107105
string::trim(mapSizes[0]);
108106
string::trim(mapSizes[1]);
109-
mapSize.x = std::stoi(mapSizes[0]);
110-
mapSize.y = std::stoi(mapSizes[1]);
107+
string::toInt(mapSizes[0], mapSize.x);
108+
string::toInt(mapSizes[1], mapSize.y);
111109
}
112110

113111
void readMaterialExclusionDirs(BufferStreamReadOnly& stream, BufferStream& backing, std::vector<std::string_view>& materialExclusionDirs) {
@@ -290,7 +288,7 @@ void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD
290288
while (stream.peek<char>() != ']') {
291289
auto& flag = field.flags.emplace_back();
292290
auto valueString = ::readFGDString(stream, backing);
293-
if (std::from_chars(valueString.data(), valueString.data() + valueString.size(), flag.value).ec != std::errc{}) {
291+
if (string::toInt(valueString, flag.value).ec != std::errc{}) {
294292
flag.value = 0;
295293
}
296294

@@ -304,7 +302,7 @@ void readEntityKeyValue(BufferStreamReadOnly& stream, BufferStream& backing, FGD
304302
}
305303
auto enabledByDefaultString = ::readFGDString(stream, backing);
306304
int enabledByDefault = 0;
307-
if (std::from_chars(enabledByDefaultString.data(), enabledByDefaultString.data() + enabledByDefaultString.size(), enabledByDefault).ec != std::errc{}) {
305+
if (string::toInt(enabledByDefaultString, enabledByDefault).ec != std::errc{}) {
308306
flag.enabledByDefault = false;
309307
} else {
310308
flag.enabledByDefault = static_cast<bool>(enabledByDefault);

src/sourcepp/parser/Text.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,26 @@ bool parser::text::isNewLine(char c) {
3131
return c == '\n' || c == '\r';
3232
}
3333

34+
bool parser::text::isNewLine(std::string_view str) {
35+
return std::all_of(str.begin(), str.end(), [](char c) { return isNewLine(c); });
36+
}
37+
3438
bool parser::text::isWhitespace(char c) {
3539
return c == ' ' || c == '\a' || c == '\f' || c == '\t' || c == '\v' || isNewLine(c);
3640
}
3741

42+
bool parser::text::isWhitespace(std::string_view str) {
43+
return std::all_of(str.begin(), str.end(), [](char c) { return isWhitespace(c); });
44+
}
45+
3846
bool parser::text::isNumber(char c) {
3947
return std::isdigit(c);
4048
}
4149

50+
bool parser::text::isNumber(std::string_view str) {
51+
return std::all_of(str.begin(), str.end(), [](char c) { return isNumber(c); });
52+
}
53+
4254
void parser::text::eatWhitespace(BufferStream& stream) {
4355
while (isWhitespace(stream.read<char>())) {}
4456
stream.seek(-1, std::ios::cur);

src/sourcepp/string/String.cpp

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,66 @@ void string::ltrim(std::string& s) {
2121
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !std::isspace(c); }));
2222
}
2323

24+
std::string_view string::ltrim(std::string_view s) {
25+
while (!s.empty() && std::isspace(s[0])) {
26+
s.remove_prefix(1);
27+
}
28+
return s;
29+
}
30+
2431
void string::rtrim(std::string& s) {
2532
s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !std::isspace(c); }).base(), s.end());
2633
}
2734

35+
std::string_view string::rtrim(std::string_view s) {
36+
while (!s.empty() && std::isspace(s[s.size() - 1])) {
37+
s.remove_suffix(1);
38+
}
39+
return s;
40+
}
41+
2842
void string::trim(std::string& s) {
2943
rtrim(s);
3044
ltrim(s);
3145
}
3246

47+
std::string_view string::trim(std::string_view s) {
48+
return ltrim(rtrim(s));
49+
}
50+
3351
void string::ltrim(std::string& s, std::string_view chars) {
3452
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [chars](char c) {
3553
return !contains(chars, c);
3654
}));
3755
}
3856

57+
std::string_view string::ltrim(std::string_view s, std::string_view chars) {
58+
while (!s.empty() && contains(chars, s[0])) {
59+
s.remove_prefix(1);
60+
}
61+
return s;
62+
}
63+
3964
void string::rtrim(std::string& s, std::string_view chars) {
4065
s.erase(std::find_if(s.rbegin(), s.rend(), [chars](char c) {
4166
return !contains(chars, c);
4267
}).base(), s.end());
4368
}
4469

45-
void string::trim(std::string& s, std::string_view c) {
46-
rtrim(s, c);
47-
ltrim(s, c);
70+
std::string_view string::rtrim(std::string_view s, std::string_view chars) {
71+
while (!s.empty() && contains(chars, s[s.size() - 1])) {
72+
s.remove_suffix(1);
73+
}
74+
return s;
75+
}
76+
77+
void string::trim(std::string& s, std::string_view chars) {
78+
rtrim(s, chars);
79+
ltrim(s, chars);
80+
}
81+
82+
std::string_view string::trim(std::string_view s, std::string_view chars) {
83+
return ltrim(rtrim(s, chars), chars);
4884
}
4985

5086
// https://stackoverflow.com/a/46931770
@@ -63,10 +99,22 @@ void string::toLower(std::string& input) {
6399
std::transform(input.begin(), input.end(), input.begin(), [](unsigned char c){ return std::tolower(c); });
64100
}
65101

102+
std::string string::toLower(std::string_view input) {
103+
std::string out{input};
104+
toLower(out);
105+
return out;
106+
}
107+
66108
void string::toUpper(std::string& input) {
67109
std::transform(input.begin(), input.end(), input.begin(), [](unsigned char c){ return std::toupper(c); });
68110
}
69111

112+
std::string string::toUpper(std::string_view input) {
113+
std::string out{input};
114+
toUpper(out);
115+
return out;
116+
}
117+
70118
std::string string::createRandom(uint16_t length, std::string_view chars) {
71119
std::random_device random_device{};
72120
std::mt19937 generator{random_device()};

0 commit comments

Comments
 (0)