1 | #pragma once |
2 | |
3 | #include <string> |
4 | #include <cstring> |
5 | #include <cstddef> |
6 | #include <type_traits> |
7 | |
8 | |
9 | namespace detail |
10 | { |
11 | bool startsWith(const std::string & s, const char * prefix, size_t prefix_size); |
12 | bool endsWith(const std::string & s, const char * suffix, size_t suffix_size); |
13 | } |
14 | |
15 | |
16 | inline bool startsWith(const std::string & s, const std::string & prefix) |
17 | { |
18 | return detail::startsWith(s, prefix.data(), prefix.size()); |
19 | } |
20 | |
21 | inline bool endsWith(const std::string & s, const std::string & suffix) |
22 | { |
23 | return detail::endsWith(s, suffix.data(), suffix.size()); |
24 | } |
25 | |
26 | |
27 | /// With GCC, strlen is evaluated compile time if we pass it a constant |
28 | /// string that is known at compile time. |
29 | inline bool startsWith(const std::string & s, const char * prefix) |
30 | { |
31 | return detail::startsWith(s, prefix, strlen(prefix)); |
32 | } |
33 | |
34 | inline bool endsWith(const std::string & s, const char * suffix) |
35 | { |
36 | return detail::endsWith(s, suffix, strlen(suffix)); |
37 | } |
38 | |
39 | /// Given an integer, return the adequate suffix for |
40 | /// printing an ordinal number. |
41 | template <typename T> |
42 | std::string getOrdinalSuffix(T n) |
43 | { |
44 | static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>, |
45 | "Unsigned integer value required" ); |
46 | |
47 | const auto last_digit = n % 10; |
48 | |
49 | if ((last_digit < 1 || last_digit > 3) |
50 | || ((n > 10) && (((n / 10) % 10) == 1))) |
51 | return "th" ; |
52 | |
53 | switch (last_digit) |
54 | { |
55 | case 1: return "st" ; |
56 | case 2: return "nd" ; |
57 | case 3: return "rd" ; |
58 | default: return "th" ; |
59 | } |
60 | } |
61 | |
62 | /// More efficient than libc, because doesn't respect locale. But for some functions table implementation could be better. |
63 | |
64 | inline bool isASCII(char c) |
65 | { |
66 | return static_cast<unsigned char>(c) < 0x80; |
67 | } |
68 | |
69 | inline bool isAlphaASCII(char c) |
70 | { |
71 | return (c >= 'a' && c <= 'z') |
72 | || (c >= 'A' && c <= 'Z'); |
73 | } |
74 | |
75 | inline bool isNumericASCII(char c) |
76 | { |
77 | /// This is faster than |
78 | /// return UInt8(UInt8(c) - UInt8('0')) < UInt8(10); |
79 | /// on Intel CPUs when compiled by gcc 8. |
80 | return (c >= '0' && c <= '9'); |
81 | } |
82 | |
83 | inline bool isHexDigit(char c) |
84 | { |
85 | return isNumericASCII(c) |
86 | || (c >= 'a' && c <= 'f') |
87 | || (c >= 'A' && c <= 'F'); |
88 | } |
89 | |
90 | inline bool isAlphaNumericASCII(char c) |
91 | { |
92 | return isAlphaASCII(c) |
93 | || isNumericASCII(c); |
94 | } |
95 | |
96 | inline bool isWordCharASCII(char c) |
97 | { |
98 | return isAlphaNumericASCII(c) |
99 | || c == '_'; |
100 | } |
101 | |
102 | inline bool isValidIdentifierBegin(char c) |
103 | { |
104 | return isAlphaASCII(c) |
105 | || c == '_'; |
106 | } |
107 | |
108 | inline bool isWhitespaceASCII(char c) |
109 | { |
110 | return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; |
111 | } |
112 | |
113 | inline bool isControlASCII(char c) |
114 | { |
115 | return static_cast<unsigned char>(c) <= 31; |
116 | } |
117 | |
118 | /// Works assuming isAlphaASCII. |
119 | inline char toLowerIfAlphaASCII(char c) |
120 | { |
121 | return c | 0x20; |
122 | } |
123 | |
124 | inline char toUpperIfAlphaASCII(char c) |
125 | { |
126 | return c & (~0x20); |
127 | } |
128 | |
129 | inline char alternateCaseIfAlphaASCII(char c) |
130 | { |
131 | return c ^ 0x20; |
132 | } |
133 | |
134 | inline bool equalsCaseInsensitive(char a, char b) |
135 | { |
136 | return a == b || (isAlphaASCII(a) && alternateCaseIfAlphaASCII(a) == b); |
137 | } |
138 | |
139 | |
140 | template <typename F> |
141 | std::string trim(const std::string & str, F && predicate) |
142 | { |
143 | size_t cut_front = 0; |
144 | size_t cut_back = 0; |
145 | size_t size = str.size(); |
146 | |
147 | for (size_t i = 0; i < size; ++i) |
148 | { |
149 | if (predicate(str[i])) |
150 | ++cut_front; |
151 | else |
152 | break; |
153 | } |
154 | |
155 | if (cut_front == size) |
156 | return {}; |
157 | |
158 | for (auto it = str.rbegin(); it != str.rend(); ++it) |
159 | { |
160 | if (predicate(*it)) |
161 | ++cut_back; |
162 | else |
163 | break; |
164 | } |
165 | |
166 | return str.substr(cut_front, size - cut_front - cut_back); |
167 | } |
168 | |