HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
strings.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/algorithm.hpp"
7#include "TTauri/Foundation/numeric_cast.hpp"
8#include "TTauri/Foundation/required.hpp"
9#include "TTauri/Foundation/assert.hpp"
10#include "TTauri/Foundation/os_detect.hpp"
11#include "TTauri/Foundation/Unicode.hpp"
12#include <string>
13#include <string_view>
14#include <iterator>
15#include <vector>
16#include <tuple>
17
18namespace tt {
19
20[[nodiscard]] constexpr bool isUpper(char c) noexcept {
21 return c >= 'A' && c <= 'Z';
22}
23
24[[nodiscard]] constexpr bool isLower(char c) noexcept {
25 return c >= 'a' && c <= 'z';
26}
27
28[[nodiscard]] constexpr bool isAlpha(char c) noexcept {
29 return isUpper(c) || isLower(c);
30}
31
32[[nodiscard]] constexpr bool isDigit(char c) noexcept {
33 return c >= '0' && c <= '9';
34}
35
36[[nodiscard]] constexpr bool isAlphaNum(char c) noexcept {
37 return isAlpha(c) || isDigit(c);
38}
39
40[[nodiscard]] constexpr bool isLinefeed(char c) noexcept {
41 return c == '\r' || c == '\n' || c == '\f' || c == '\v';
42}
43
44[[nodiscard]] constexpr bool isWhitespace(char c) noexcept {
45 return c == ' ' || c == '\t' || isLinefeed(c);
46}
47
48[[nodiscard]] constexpr bool isNumberFirst(char c) noexcept {
49 return isDigit(c) || c == '+' || c == '-';
50}
51
52[[nodiscard]] constexpr bool isNameFirst(char c) noexcept {
53 return isAlpha(c) || c == '_' || c == '$';
54}
55
56[[nodiscard]] constexpr bool isNameNext(char c) noexcept {
57 return isAlphaNum(c) || c == '_' || c == '$';
58}
59
60[[nodiscard]] constexpr bool isQuote(char c) noexcept {
61 return c == '"' || c == '\'' || c == '`';
62}
63
64[[nodiscard]] constexpr bool isOpenBracket(char c) noexcept {
65 return c == '(' || c == '{' || c == '[';
66}
67
68[[nodiscard]] constexpr bool isCloseBracket(char c) noexcept {
69 return c == ')' || c == '}' || c == ']';
70}
71
72[[nodiscard]] constexpr bool isOperator(char c) noexcept {
73 return
74 !isAlphaNum(c) && c != '_' &&
75 !isWhitespace(c) &&
76 !isQuote(c) &&
77 !isOpenBracket(c) &&
78 !isCloseBracket(c);
79}
80
81[[nodiscard]] inline std::string to_lower(std::string_view str) noexcept
82{
84 r.reserve(size(str));
85
86 for (ttlet c: str) {
87 r += (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a': c;
88 }
89
90 return r;
91}
92
93[[nodiscard]] inline std::string to_upper(std::string_view str) noexcept
94{
96 r.reserve(size(str));
97
98 for (ttlet c: str) {
99 r += (c >= 'a' && c <= 'z') ? (c - 'a') + 'A': c;
100 }
101
102 return r;
103}
104
107[[nodiscard]] inline std::string normalize_lf(std::string_view str) noexcept
108{
109 std::string r;
110 r.reserve(size(str));
111
112 auto found_cr = false;
113 for (ttlet c: str) {
114 if (tt_unlikely(found_cr)) {
115 // This is Microsoft or old-Apple, we replace the previous carriage-return
116 // with a line-feed and emit the current character.
117 r += '\n';
118 if (c != '\r' && c != '\n') {
119 r += c;
120 }
121
122 } else if (tt_likely(c != '\r')) {
123 // Emit any non-carriage return character.
124 r += c;
125 }
126
127 found_cr = c == '\r';
128 }
129 if (found_cr) {
130 r += '\n';
131 }
132
133 return r;
134}
135
139[[nodiscard]] inline std::string id_encode(std::string_view str) noexcept
140{
141 std::string r;
142 r.reserve(size(str));
143
144 r += isNameFirst(str.front()) ? str.front() : '_';
145 for (ttlet c: str.substr(1)) {
146 r += isNameNext(c) ? c : '_';
147 }
148
149 return r;
150}
151
152gsl_suppress3(f.23,bounds.1,bounds.3)
153[[nodiscard]] constexpr uint32_t fourcc(char const txt[5]) noexcept
154{
155 return (
156 (static_cast<uint32_t>(txt[0]) << 24) |
157 (static_cast<uint32_t>(txt[1]) << 16) |
158 (static_cast<uint32_t>(txt[2]) << 8) |
159 static_cast<uint32_t>(txt[3])
160 );
161}
162
163[[nodiscard]] constexpr uint32_t fourcc(uint8_t const *txt) noexcept
164{
165 return (
166 (static_cast<uint32_t>(txt[0]) << 24) |
167 (static_cast<uint32_t>(txt[1]) << 16) |
168 (static_cast<uint32_t>(txt[2]) << 8) |
169 static_cast<uint32_t>(txt[3])
170 );
171}
172
173gsl_suppress(bounds.3)
174[[nodiscard]] inline std::string fourcc_to_string(uint32_t x) noexcept
175{
176 char c_str[5];
177 c_str[0] = numeric_cast<char>((x >> 24) & 0xff);
178 c_str[1] = numeric_cast<char>((x >> 16) & 0xff);
179 c_str[2] = numeric_cast<char>((x >> 8) & 0xff);
180 c_str[3] = numeric_cast<char>(x & 0xff);
181 c_str[4] = 0;
182
183 return {c_str};
184}
185
186[[nodiscard]] constexpr char nibble_to_char(uint8_t nibble) noexcept
187{
188 if (nibble <= 9) {
189 return '0' + nibble;
190 } else if (nibble <= 15) {
191 return 'a' + nibble - 10;
192 } else {
193 tt_no_default;
194 }
195}
196
200[[nodiscard]] inline int8_t char_to_nibble(char c) noexcept
201{
202 if (c >= '0' && c <= '9') {
203 return c - '0';
204 } else if (c >= 'a' && c <= 'f') {
205 return (c - 'a') + 10;
206 } else if (c >= 'A' && c <= 'F') {
207 return (c - 'A') + 10;
208 } else {
209 return -1;
210 }
211}
212
213[[nodiscard]] inline std::string_view make_string_view(
214 typename std::string::const_iterator b,
215 typename std::string::const_iterator e
216) noexcept
217{
218 return (b != e) ?
219 std::string_view{&(*b), numeric_cast<size_t>(std::distance(b, e))} :
220 std::string_view{};
221}
222
223template<typename Needle>
224[[nodiscard]] size_t split_needle_size(Needle const &needle) noexcept
225{
226 return size(needle);
227}
228
229template<>
230[[nodiscard]] inline size_t split_needle_size(char const &needle) noexcept
231{
232 return 1;
233}
234
235template<int N>
236[[nodiscard]] inline size_t split_needle_size(char const (&needle)[N]) noexcept
237{
238 return N - 1;
239}
240
241
242template<typename Haystack, typename... Needles>
243[[nodiscard]] auto split_find_needle(size_t offset, Haystack const &haystack, Needles const &... needles) noexcept
244{
245 return std::min(
246 {std::pair{haystack.find(needles, offset), split_needle_size(needles)}...},
247 [](ttlet &a, ttlet &b) {
248 return a.first < b.first;
249 }
250 );
251}
252
253template<typename Haystack, typename... Needles>
254[[nodiscard]] auto split(Haystack const &haystack, Needles const &... needles) noexcept
255{
257
258 size_t offset = 0;
259 size_t needle_pos;
260 size_t needle_size;
261
262 std::tie(needle_pos, needle_size) = split_find_needle(offset, haystack, needles...);
263 while (needle_pos != haystack.npos) {
264 r.push_back(haystack.substr(offset, needle_pos - offset));
265
266 offset = needle_pos + needle_size;
267 std::tie(needle_pos, needle_size) = split_find_needle(offset, haystack, needles...);
268 }
269
270 r.push_back(haystack.substr(offset));
271 return r;
272}
273
274[[nodiscard]] inline std::string join(std::vector<std::string> const &list, std::string_view const joiner = {}) noexcept
275{
276 std::string r;
277
278 if (list.size() > 1) {
279 size_t final_size = (list.size() - 1) * joiner.size();
280 for (ttlet &item: list) {
281 final_size += item.size();
282 }
283 r.reserve(final_size);
284 }
285
286 int64_t i = 0;
287 for (ttlet &item: list) {
288 if (i++ > 0) {
289 r += joiner;
290 }
291 r += item;
292 }
293 return r;
294}
295
296[[nodiscard]] inline std::string join(std::vector<std::string_view> const &list, std::string_view const joiner = {}) noexcept
297{
298 std::string r;
299
300 if (list.size() > 1) {
301 size_t final_size = (list.size() - 1) * joiner.size();
302 for (ttlet &item: list) {
303 final_size += item.size();
304 }
305 r.reserve(final_size);
306 }
307
308 int64_t i = 0;
309 for (ttlet &item: list) {
310 if (i++ > 0) {
311 r += joiner;
312 }
313 r += item;
314 }
315 return r;
316}
317
318
319
322template<typename It>
323[[nodiscard]] inline std::pair<int,int> count_line_and_columns(It begin, It const end)
324{
325 int line = 1;
326 int column = 1;
327
328 for (; begin != end; begin++) {
329 switch (*begin) {
330 case '\n': line++; [[fallthrough]];
331 case '\r': column = 1;
332 break;
333 case '\t':
334 column = ((((column-1) / 8) + 1) * 8) + 1;
335 break;
336 default:
337 column++;
338 }
339 }
340 return { line, column };
341}
342
343}
Definition range_map.hpp:119
T begin(T... args)
T distance(T... args)
T end(T... args)
T min(T... args)
T push_back(T... args)
T reserve(T... args)
T size(T... args)
T tie(T... args)