chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
93 / 96
96.9%
Branches:
67 / 68
98.5%
Functions:
14 / 14
100.0%

util/text.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #include "chrono_batch_render/util/text.h"
3
4 #include <algorithm>
5 #include <cctype>
6 #include <cstdint>
7
8 #include <fmt/format.h>
9
10 #include "chrono_batch_render/util/error.h"
11
12 namespace chrono::batch_render {
13
14 373 std::string Lowercase(std::string_view text) {
15 373 std::string lower(text);
16 373 std::ranges::transform(lower, lower.begin(),
17 1420 [](unsigned char c) { return char(std::tolower(c)); });
18 373 return lower;
19 }
20
21 1431 std::string Join(const std::vector<std::string>& parts, std::string_view separator) {
22 1431 std::string joined;
23
2/2
✓ Branch 0 taken 2191 times.
✓ Branch 1 taken 1431 times.
3622 for (const std::string& part : parts) {
24
2/2
✓ Branch 0 taken 763 times.
✓ Branch 1 taken 1428 times.
2191 if (!joined.empty()) {
25
1/1
✓ Branch 1 taken 763 times.
763 joined += separator;
26 }
27
1/1
✓ Branch 1 taken 2191 times.
4382 joined += part;
28 }
29 1431 return joined;
30 ✗ }
31
32 118707 std::vector<std::string_view> Split(std::string_view text, char separator) {
33 118707 std::vector<std::string_view> parts;
34 118707 size_t start = 0;
35
2/2
✓ Branch 0 taken 34249 times.
✓ Branch 1 taken 118707 times.
152956 for (size_t end = text.find(separator); end != std::string_view::npos;
36 34249 end = text.find(separator, start)) {
37
1/1
✓ Branch 1 taken 34249 times.
34249 parts.push_back(text.substr(start, end - start));
38 34249 start = end + 1;
39 }
40
1/1
✓ Branch 1 taken 118707 times.
118707 parts.push_back(text.substr(start));
41 118707 return parts;
42 ✗ }
43
44 83278 std::pair<std::string_view, std::string_view> SplitLast(std::string_view text, char separator) {
45 83278 const size_t at = text.rfind(separator);
46
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 83277 times.
83278 if (at == std::string_view::npos) {
47 1 return {std::string_view(), text};
48 }
49 83277 return {text.substr(0, at), text.substr(at + 1)};
50 }
51
52 59223 bool IsIdentifier(std::string_view text) {
53 651238 const auto letter = [](char c) {
54
3/3
✓ Branch 0 taken 260940 times.
✓ Branch 1 taken 35505 times.
✓ Branch 2 taken 295570 times.
592015 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_';
55 };
56
4/4
✓ Branch 0 taken 295567 times.
✓ Branch 1 taken 237226 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 295560 times.
532793 const auto letterOrDigit = [&](char c) { return letter(c) || (c >= '0' && c <= '9'); };
57
6/6
✓ Branch 0 taken 59222 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 59219 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 59212 times.
59223 return !text.empty() && letter(text[0]) &&
58
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 59212 times.
59219 std::all_of(text.begin() + 1, text.end(), letterOrDigit);
59 }
60
61 3532 bool Glob(std::string_view pattern, std::string_view text) {
62 3532 size_t p = 0;
63 3532 size_t t = 0;
64 3532 size_t star = std::string_view::npos;
65 3532 size_t resume = 0;
66
2/2
✓ Branch 0 taken 11801 times.
✓ Branch 1 taken 1186 times.
12987 while (t < text.size()) {
67
6/6
✓ Branch 0 taken 9639 times.
✓ Branch 1 taken 2162 times.
✓ Branch 2 taken 9637 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6073 times.
✓ Branch 5 taken 3564 times.
11801 if (p < pattern.size() && (pattern[p] == '?' || pattern[p] == text[t])) {
68 6075 ++p;
69 6075 ++t;
70
4/4
✓ Branch 0 taken 3564 times.
✓ Branch 1 taken 2162 times.
✓ Branch 2 taken 2545 times.
✓ Branch 3 taken 1019 times.
5726 } else if (p < pattern.size() && pattern[p] == '*') {
71 1019 star = p++;
72 1019 resume = t;
73
2/2
✓ Branch 0 taken 2361 times.
✓ Branch 1 taken 2346 times.
4707 } else if (star != std::string_view::npos) {
74 2361 p = star + 1;
75 2361 t = ++resume;
76 } else {
77 return false;
78 }
79 }
80
81
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1183 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 time.
1187 while (p < pattern.size() && pattern[p] == '*') {
82 1 ++p;
83 }
84 1186 return p == pattern.size();
85 }
86
87 47678 uint64_t Fnv1a(std::string_view bytes, uint64_t hash) {
88
2/2
✓ Branch 0 taken 581262426 times.
✓ Branch 1 taken 47678 times.
581310104 for (const char byte : bytes) {
89 581262426 hash = (hash ^ uint8_t(byte)) * 0x100000001b3ull;
90 }
91 47678 return hash;
92 }
93
94 41740 std::string Digest(std::string_view bytes) {
95 41740 return fmt::format("{:016x}", Fnv1a(bytes));
96 }
97
98 std::string
99 515 FillTemplate(std::string_view text,
100 std::initializer_list<std::pair<std::string_view, std::string_view>> values) {
101 515 std::string filled;
102 515 size_t at = 0;
103 6187 while (true) {
104 3351 const size_t open = text.find("{{", at);
105
2/2
✓ Branch 0 taken 513 times.
✓ Branch 1 taken 2838 times.
3351 if (open == std::string_view::npos) {
106
1/1
✓ Branch 1 taken 513 times.
513 filled += text.substr(at);
107 513 return filled;
108 }
109 2838 const size_t close = text.find("}}", open + 2);
110
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2837 times.
2838 if (close == std::string_view::npos) {
111
1/1
✓ Branch 2 taken 1 time.
1 throw Error("A template opens a placeholder at byte {} and never closes it", open);
112 }
113
1/1
✓ Branch 1 taken 2837 times.
2837 const std::string_view name = text.substr(open + 2, close - open - 2);
114 2837 const auto found =
115 2837 std::ranges::find(values, name, &std::pair<std::string_view, std::string_view>::first);
116
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2836 times.
2837 if (found == values.end()) {
117
1/1
✓ Branch 2 taken 1 time.
1 throw Error("A template uses {{{{{}}}}}, which nothing fills", name);
118 }
119
1/1
✓ Branch 1 taken 2836 times.
2838 filled += text.substr(at, open - at);
120
1/1
✓ Branch 1 taken 2836 times.
2836 filled += found->second;
121 2836 at = close + 2;
122 2836 }
123 2 }
124
125 42 std::string Replaced(std::string text, std::string_view from, std::string_view to) {
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (from.empty()) {
127 ✗ return text;
128 }
129
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 42 times.
50 for (size_t at = text.find(from); at != std::string::npos; at = text.find(from, at)) {
130 8 text.replace(at, from.size(), to);
131 8 at += to.size();
132 }
133 42 return text;
134 }
135
136 510 std::string ModulePath(std::string_view module) {
137 510 std::string path(module);
138 510 std::ranges::replace(path, '.', '/');
139
1/1
✓ Branch 1 taken 510 times.
510 return path + ".slang";
140 510 }
141
142 11 std::string MapOrigins(std::string message,
143 std::span<const std::pair<std::string, std::string>> origins) {
144
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 11 times.
32 for (const auto& [generated, origin] : origins) {
145 21 message =
146
2/2
✓ Branch 3 taken 21 times.
✓ Branch 6 taken 21 times.
21 Replaced(Replaced(std::move(message), "./" + generated, origin), generated, origin);
147 }
148 11 return message;
149 }
150
151 }
152