GCC Code Coverage Report


Directory: include/ezlibs/
Date: 2025-07-28 14:06:36
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Exec Total Coverage
Lines: 3063 3264 93.8%
Functions: 987 1003 98.4%
Branches: 2157 2599 83.0%
Decisions: 645 834 77.3%
Calls: 3439 4289 80.2%

Overall list of functions

File Lines Functions Branches Decisions Calls
ezAABBCC.hpp 100.0 100.0% 23 / 23 100.0% 5 / 5 -% 0 / 0 -% 0 / 0 100.0% 19 / 19
ezArgs.hpp 88.5 88.5% 201 / 227 100.0% 25 / 25 75.8% 194 / 256 77.9% 95 / 122 66.6% 257 / 386
ezBmp.hpp 94.3 94.3% 50 / 53 100.0% 6 / 6 72.7% 16 / 22 66.7% 8 / 12 80.0% 20 / 25
ezBuildInc.hpp 97.0 97.0% 131 / 135 100.0% 18 / 18 92.3% 155 / 168 76.1% 35 / 46 84.6% 204 / 241
ezCmdProcessor.hpp 100.0 100.0% 60 / 60 100.0% 5 / 5 87.7% 50 / 57 78.1% 25 / 32 89.3% 67 / 75
ezCnt.hpp 92.9 92.9% 13 / 14 100.0% 6 / 6 80.0% 4 / 5 75.0% 3 / 4 100.0% 12 / 12
ezCron.hpp 95.4 95.4% 267 / 280 100.0% 25 / 25 92.1% 234 / 254 91.7% 132 / 144 82.2% 244 / 297
ezExpr.hpp 94.7 94.7% 408 / 431 97.8% 87 / 89 88.8% 419 / 472 63.6% 14 / 22 70.8% 658 / 929
ezFigFont.hpp 96.9 96.9% 95 / 98 100.0% 9 / 9 92.0% 80 / 87 72.7% 32 / 44 83.2% 104 / 125
ezFile.hpp 75.0 75.0% 24 / 32 100.0% 2 / 2 52.6% 20 / 38 33.3% 4 / 12 45.5% 30 / 66
ezGL/uniforms.hpp 95.7 95.7% 135 / 141 100.0% 6 / 6 72.6% 146 / 201 80.0% 16 / 20 80.0% 168 / 210
ezGraph.hpp 98.4 98.4% 182 / 185 100.0% 51 / 51 75.6% 62 / 82 68.8% 33 / 48 90.9% 229 / 252
ezLog.hpp 76.3 76.3% 58 / 76 88.9% 8 / 9 56.7% 38 / 67 45.8% 11 / 24 70.6% 48 / 68
ezMath.hpp 100.0 100.0% 70 / 70 100.0% 79 / 79 100.0% 24 / 24 100.0% 6 / 6 96.7% 29 / 30
ezNamedPipe.hpp 87.9 87.9% 51 / 58 100.0% 12 / 12 69.7% 23 / 33 68.2% 15 / 22 91.5% 43 / 47
ezSha.hpp 97.1 97.1% 166 / 171 100.0% 12 / 12 81.2% 26 / 32 73.3% 22 / 30 99.6% 262 / 263
ezStackString.hpp 99.0 99.0% 96 / 97 100.0% 46 / 46 84.3% 43 / 51 95.5% 21 / 22 80.5% 33 / 41
ezStr.hpp 80.2 80.2% 65 / 81 92.3% 12 / 13 77.6% 45 / 58 75.0% 21 / 28 78.0% 46 / 59
ezTime.hpp 100.0 100.0% 2 / 2 100.0% 1 / 1 100.0% 1 / 1 -% 0 / 0 100.0% 4 / 4
ezVdbWriter.hpp 97.6 97.6% 243 / 249 96.8% 60 / 62 81.0% 128 / 158 76.5% 26 / 34 85.0% 216 / 254
ezVec2.hpp 98.6 98.6% 72 / 73 100.0% 160 / 160 80.0% 12 / 15 50.0% 1 / 2 100.0% 49 / 49
ezVec3.hpp 98.3 98.3% 58 / 59 100.0% 143 / 143 71.8% 28 / 39 50.0% 1 / 2 87.2% 41 / 47
ezVec4.hpp 98.3 98.3% 57 / 58 100.0% 128 / 128 75.0% 33 / 44 50.0% 1 / 2 83.9% 47 / 56
ezVoxWriter.hpp 93.8 93.8% 333 / 355 96.1% 49 / 51 88.3% 212 / 240 70.8% 51 / 72 87.5% 393 / 449
ezXml.hpp 86.0 86.0% 203 / 236 80.0% 32 / 40 84.1% 164 / 195 85.7% 72 / 84 75.8% 216 / 285

Directory: include/ezlibs/
File: ezTime.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 2 2 100.0%
Functions: 1 1 100.0%
Branches: 1 1 100.0%
Decisions: 0 0 -%
Calls: 4 4 100.0%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezTime is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include "ezOS.hpp"
30
31 #include <ctime>
32 #include <string>
33 #include <chrono>
34 #include <iomanip>
35 #include <sstream>
36 #include <cstdint>
37
38 #ifndef EZ_TIME
39 #define EZ_TIME
40 #endif // EZ_TIME
41
42 namespace ez {
43 namespace time {
44
45 // convert a string ISO8601 time to epoch time
46 inline bool iso8601ToEpoch(const std::string& vIsoDateTime, const std::string& vTimeFormat, std::time_t& vOutTime) {
47 if (!vIsoDateTime.empty() && !vTimeFormat.empty()) {
48 struct std::tm time = {};
49 std::istringstream iss(vIsoDateTime);
50 iss >> std::get_time(&time, vTimeFormat.c_str());
51 if (!iss.fail()) {
52 time.tm_hour = 0;
53 time.tm_min = 0;
54 time.tm_sec = 0;
55 #ifdef WINDOWS_OS
56 vOutTime = _mkgmtime(&time);
57 #else
58 vOutTime = timegm(&time);
59 #endif
60 return true;
61 }
62 }
63 return false;
64 }
65
66 // convert a epoch time to a string ISO8601 time
67 inline bool epochToISO8601(const std::time_t& vEpochTime, std::string& vOutTime) {
68 auto tp = std::chrono::system_clock::from_time_t(vEpochTime);
69 auto tt = std::chrono::system_clock::to_time_t(tp);
70 #ifdef _MSC_VER
71 tm _timeinfo;
72 tm* pTimeInfo = &_timeinfo;
73 if (localtime_s(pTimeInfo, &tt) != 0) {
74 return false;
75 }
76 #else
77 auto* pTimeInfo = std::localtime(&tt);
78 #endif
79 std::ostringstream oss;
80 oss << std::put_time(pTimeInfo, "%Y-%m-%d");
81 if (!oss.fail()) {
82 vOutTime = oss.str();
83 return true;
84 }
85 return false;
86 }
87
88 // TODO: TO TEST
89 inline tm decomposeEpoch(const std::time_t& vEpochTime) {
90 tm ret{};
91 auto tp = std::chrono::system_clock::from_time_t(vEpochTime);
92 auto tt = std::chrono::system_clock::to_time_t(tp);
93 #ifdef _MSC_VER
94 tm _timeinfo;
95 tm* pTimeInfo = &_timeinfo;
96 if (localtime_s(pTimeInfo, &tt) != 0) {
97 return ret;
98 }
99 #else
100 auto* pTimeInfo = std::localtime(&tt);
101 #endif
102 ret = *pTimeInfo;
103 return ret;
104 }
105
106 // TODO: TO TEST
107 inline std::string getCurrentDate() {
108 auto curr_date_t = std::time(nullptr);
109 #ifdef _MSC_VER
110 tm _timeinfo;
111 tm* tm_curr_date = &_timeinfo;
112 if (localtime_s(tm_curr_date, &curr_date_t) != 0) {
113 return {};
114 }
115 #else
116 auto* tm_curr_date = std::localtime(&curr_date_t);
117 #endif
118 char buffer[32 + 1]{};
119 auto s = strftime(buffer, 32, "%Y-%m-%d", tm_curr_date);
120 buffer[s] = '\0';
121 return std::string(buffer);
122 }
123
124 // TODO: TO TEST
125 inline std::string getCurrentDate(size_t vHoursOffset) {
126 auto curr_date_t = std::time(nullptr);
127 #ifdef _MSC_VER
128 tm _timeinfo;
129 tm* tm_curr_date = &_timeinfo;
130 if (localtime_s(tm_curr_date, &curr_date_t) != 0) {
131 return {};
132 }
133 #else
134 std::localtime(&curr_date_t);
135 #endif
136 std::chrono::hours offset_hours(vHoursOffset);
137 auto curr_date = std::chrono::system_clock::from_time_t(curr_date_t);
138 auto offset_date_t = std::chrono::system_clock::to_time_t(curr_date + offset_hours);
139 #ifdef _MSC_VER
140 tm* tm_offset_date = &_timeinfo;
141 if (localtime_s(tm_offset_date, &offset_date_t) != 0) {
142 return {};
143 }
144 #else
145 auto* tm_offset_date = std::localtime(&offset_date_t);
146 #endif
147 char buffer[32+1]{};
148 auto s = strftime(buffer, 32, "%Y-%m-%d", tm_offset_date);
149 buffer[s] = '\0';
150 return std::string(buffer);
151 }
152
153 127 inline uint64_t getTicks() {
154
1/1
✓ Branch 3 taken 127 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
127 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
155 }
156
157 // TODO: TO TEST
158 inline float getTimeInterval() {
159 static auto S_lastTick = getTicks();
160 const uint64_t ticks = getTicks();
161 static float secMult = 1.0f / 1000.0f;
162 const float interval = (ticks - S_lastTick) * secMult;
163 S_lastTick = ticks;
164 return interval;
165 }
166
167 // TODO: TO TEST
168 class ActionTime {
169 private:
170 uint64_t m_LastTick = 0U;
171 uint64_t m_PauseTick = 0U;
172 uint64_t m_ResumeTick = 0U;
173 bool m_Play = true;
174
175 public:
176 ActionTime() {
177 m_LastTick = getTicks();
178 }
179
180 void fix() { // fixe les marqueur de temps
181 m_LastTick = getTicks();
182 m_PauseTick = getTicks();
183 m_ResumeTick = getTicks();
184 }
185
186 void fixTime(double vValue) { // fixe les marqueur de temps
187 fix();
188 setTime(vValue);
189 }
190
191 void pause() {
192 m_PauseTick = getTicks();
193 m_Play = false;
194 }
195
196 void resume() {
197 m_ResumeTick = getTicks();
198 m_LastTick += m_ResumeTick - m_PauseTick;
199 m_Play = true;
200 }
201
202 uint64_t get() const {
203 return getTicks() - m_LastTick;
204 }
205
206 double getTime() const {
207 static double secMult = 1e-3;
208 return (getTicks() - m_LastTick) * secMult;
209 }
210
211 void setTime(double vValue){ // set le temps
212 const auto v = (uint64_t)(vValue * 1000.0);
213 m_LastTick = getTicks() - v;
214 }
215
216 // verifie si vMs millisecond depuis le dernier fix et donc si on peut agir
217 // vFix permet de fixer le temps pour la prochaine action
218 // on pourrait vouloir interroger sans vouloir permettre la prochaine action
219 bool isTimeToAct(long vMs, bool vFix) {
220 if (get() > (uint64_t)vMs) {
221 if (vFix) {
222 fix();
223 }
224 return true;
225 }
226 return false;
227 }
228 };
229
230 // TODO: TO TEST
231 //! Measure the time in microsecondes of a operation passed via lambda fucntion
232 //! the operation will be executed many time according to vCountOperations and averaged
233 template <typename TLAMBDA>
234 double measureOperationUs(TLAMBDA vLambda, size_t vCountOperations = 1) {
235 using clock = std::chrono::high_resolution_clock;
236 std::chrono::duration<double, std::micro> total{0};
237 for (size_t i = 0; i < vCountOperations; ++i) {
238 auto t0 = clock::now();
239 vLambda();
240 total += clock::now() - t0;
241 }
242 if (vCountOperations > 1) {
243 total /= static_cast<double>(vCountOperations);
244 }
245 return total.count();
246 }
247
248 } // namespace time
249 } // namespace ez
250

Directory: include/ezlibs/
File: ezStr.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 65 81 80.2%
Functions: 12 13 92.3%
Branches: 45 58 77.6%
Decisions: 21 28 75.0%
Calls: 46 59 78.0%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezStr is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #ifndef EZ_STR
30 #define EZ_STR
31 #endif // EZ_STR
32
33 #include <ios>
34 #include <set>
35 #include <list>
36 #include <cmath>
37 #include <vector>
38 #include <limits>
39 #include <string>
40 #include <sstream>
41 #include <iomanip>
42 #include <cstdint>
43 #include <cstdarg>
44 #include <clocale> // std::setlocale
45 #include <locale> // toupper, tolower (with locale)
46
47 #if defined(_MSC_VER) || defined(__MINGW32__)
48 #include <cwchar>
49 #include "Windows.h"
50 #endif
51
52 ////////////////////////////////////////////////////////////////////////////
53 ////////////////////////////////////////////////////////////////////////////
54 ////////////////////////////////////////////////////////////////////////////
55
56 #if defined(_MSC_VER) || defined(__MINGW32__)
57 #pragma warning(push)
58 #pragma warning(disable : 4244) // Conversion from 'double' to 'float', possible loss of data
59 #pragma warning(disable : 4305) // Truncation from 'double' to 'float'
60 #elif defined(__GNUC__) || defined(__clang__)
61 #pragma GCC diagnostic push
62 #pragma GCC diagnostic ignored "-Wconversion"
63 #pragma GCC diagnostic ignored "-Wfloat-conversion"
64 #endif
65
66 ////////////////////////////////////////////////////////////////////////////
67 ////////////////////////////////////////////////////////////////////////////
68 ////////////////////////////////////////////////////////////////////////////
69
70 namespace ez {
71 namespace str {
72
73 inline std::list<std::string> splitStringToList(const std::string& text, const std::string& delimiters, bool pushEmpty = false, bool vInversion = false) {
74 std::list<std::string> arr;
75 if (!text.empty()) {
76 std::string::size_type start = 0;
77 std::string::size_type end = text.find_first_of(delimiters, start);
78 while (end != std::string::npos) {
79 std::string token = text.substr(start, end - start);
80 if (!token.empty() || (token.empty() && pushEmpty)) {
81 if (vInversion)
82 arr.emplace_front(token);
83 else
84 arr.emplace_back(token);
85 }
86 start = end + 1;
87 end = text.find_first_of(delimiters, start);
88 }
89 std::string token = text.substr(start);
90 if (!token.empty() || (token.empty() && pushEmpty)) {
91 if (vInversion)
92 arr.emplace_front(token);
93 else
94 arr.emplace_back(token);
95 }
96 }
97 return arr;
98 }
99
100 inline std::vector<std::string> splitStringToVector(const std::string& text, const std::string& delimiters, bool pushEmpty = false) {
101 std::vector<std::string> arr;
102 if (!text.empty()) {
103 std::string::size_type start = 0;
104 std::string::size_type end = text.find_first_of(delimiters, start);
105 while (end != std::string::npos) {
106 std::string token = text.substr(start, end - start);
107 if (!token.empty() || (token.empty() && pushEmpty))
108 arr.emplace_back(token);
109 start = end + 1;
110 end = text.find_first_of(delimiters, start);
111 }
112 std::string token = text.substr(start);
113 if (!token.empty() || (token.empty() && pushEmpty))
114 arr.emplace_back(token);
115 }
116 return arr;
117 }
118
119 inline std::set<std::string> splitStringToSet(const std::string& text, const std::string& delimiters, bool pushEmpty = false) {
120 std::set<std::string> arr;
121 if (!text.empty()) {
122 std::string::size_type start = 0;
123 std::string::size_type end = text.find_first_of(delimiters, start);
124 while (end != std::string::npos) {
125 std::string token = text.substr(start, end - start);
126 if (!token.empty() || (token.empty() && pushEmpty))
127 arr.emplace(token);
128 start = end + 1;
129 end = text.find_first_of(delimiters, start);
130 }
131 std::string token = text.substr(start);
132 if (!token.empty() || (token.empty() && pushEmpty))
133 arr.emplace(token);
134 }
135 return arr;
136 }
137
138 inline std::list<std::string> splitStringToList(const std::string& text, char delimiter, bool pushEmpty = false, bool vInversion = false) {
139 std::list<std::string> arr;
140 if (!text.empty()) {
141 std::string::size_type start = 0;
142 std::string::size_type end = text.find(delimiter, start);
143 while (end != std::string::npos) {
144 std::string token = text.substr(start, end - start);
145 if (!token.empty() || (token.empty() && pushEmpty)) {
146 if (vInversion)
147 arr.emplace_front(token);
148 else
149 arr.emplace_back(token);
150 }
151 start = end + 1;
152 end = text.find(delimiter, start);
153 }
154 std::string token = text.substr(start);
155 if (!token.empty() || (token.empty() && pushEmpty)) {
156 if (vInversion)
157 arr.emplace_front(token);
158 else
159 arr.emplace_back(token);
160 }
161 }
162 return arr;
163 }
164
165 32 inline std::vector<std::string> splitStringToVector(const std::string& text, char delimiter, bool pushEmpty = false) {
166
1/1
✓ Call 0 invoked.
32 std::vector<std::string> arr;
167
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 32 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
32 if (!text.empty()) {
168 32 std::string::size_type start = 0;
169
1/1
✓ Call 0 invoked.
32 std::string::size_type end = text.find(delimiter, start);
170
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 32 times.
2/2
✓ Decision 'true' taken 23 times.
✓ Decision 'false' taken 32 times.
55 while (end != std::string::npos) {
171
1/1
✓ Branch 1 taken 23 times.
1/1
✓ Call 0 invoked.
23 std::string token = text.substr(start, end - start);
172
6/8
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 22 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 22 times.
✓ Branch 9 taken 1 times.
2/2
✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
23 if (!token.empty() || (token.empty() && pushEmpty))
173
1/1
✓ Branch 1 taken 22 times.
1/1
✓ Call 0 invoked.
22 arr.emplace_back(token);
174 23 start = end + 1;
175
1/1
✓ Call 0 invoked.
23 end = text.find(delimiter, start);
176
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
23 }
177
1/1
✓ Branch 1 taken 32 times.
1/1
✓ Call 0 invoked.
32 std::string token = text.substr(start);
178
6/8
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 31 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 31 times.
✓ Branch 9 taken 1 times.
2/2
✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
32 if (!token.empty() || (token.empty() && pushEmpty))
179
1/1
✓ Branch 1 taken 31 times.
1/1
✓ Call 0 invoked.
31 arr.emplace_back(token);
180
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
32 }
181 32 return arr;
182 }
183
184 inline std::set<std::string> splitStringToSet(const std::string& text, char delimiter, bool pushEmpty = false) {
185 std::set<std::string> arr;
186 if (!text.empty()) {
187 std::string::size_type start = 0;
188 std::string::size_type end = text.find(delimiter, start);
189 while (end != std::string::npos) {
190 std::string token = text.substr(start, end - start);
191 if (!token.empty() || (token.empty() && pushEmpty))
192 arr.emplace(token);
193 start = end + 1;
194 end = text.find(delimiter, start);
195 }
196 std::string token = text.substr(start);
197 if (!token.empty() || (token.empty() && pushEmpty))
198 arr.emplace(token);
199 }
200 return arr;
201 }
202
203 template <typename T>
204 inline bool stringToNumber(const std::string& vText, T& vNumber) {
205 try {
206 std::stringstream ss(vText);
207 ss >> vNumber;
208 } catch (std::exception&) {
209 return false;
210 }
211 return true;
212 }
213
214 template <typename T>
215 inline std::vector<T> stringToNumberVector(const std::string& text, char delimiter) {
216 std::vector<T> arr;
217 std::string::size_type start = 0;
218 std::string::size_type end = text.find(delimiter, start);
219 T value = 0;
220 while (end != std::string::npos) {
221 std::string token = text.substr(start, end - start);
222 if (stringToNumber<T>(token, value)) {
223 arr.emplace_back(value);
224 }
225 start = end + 1;
226 end = text.find(delimiter, start);
227 }
228 if (stringToNumber<T>(text.substr(start).c_str(), value)) {
229 arr.emplace_back(value);
230 }
231 return arr;
232 }
233
234 inline std::string toStr(const char* fmt, ...) {
235 va_list args;
236 va_start(args, fmt);
237 char TempBuffer[3072 + 1]; // 3072 = 1024 * 3
238 const int w = vsnprintf(TempBuffer, 3072, fmt, args);
239 va_end(args);
240
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (w) {
241
0/1
✗ Call 0 not invoked.
return std::string(TempBuffer, (size_t)w);
242 }
243
0/1
✗ Call 0 not invoked.
return std::string();
244 }
245
246 inline std::string toUpper(const std::string& vStr, const std::locale& vLocale = {}) {
247 std::string str = vStr;
248 for (size_t i = 0U; i < str.size(); ++i) {
249 str[i] = ::std::toupper(str[i], vLocale);
250 }
251 return str;
252 }
253
254 inline std::string toLower(const std::string& vStr, const std::locale& vLocale = {}) {
255 std::string str = vStr;
256 for (size_t i = 0U; i < str.size(); ++i) {
257 str[i] = ::std::tolower(str[i], vLocale);
258 }
259 return str;
260 }
261
262 inline std::string toHex(const std::string& vStr) {
263 if (!vStr.empty()) {
264 std::stringstream ss;
265 ss << std::setfill('0') << std::setw(2) << std::hex;
266 for (const auto& c : vStr) {
267 ss << (0xff & (unsigned int)c);
268 }
269 return ss.str();
270 }
271 return {};
272 }
273
274 template <typename T>
275 inline std::string toStrFromArray(T* arr, size_t n, char delimiter = ';') {
276 if (arr) {
277 std::ostringstream os;
278 for (size_t i = 0; i < n; ++i) {
279 os << arr[i];
280 if (i < n - 1)
281 os << delimiter;
282 }
283 return os.str();
284 }
285 return "";
286 }
287
288 template <typename T>
289 318 inline std::string toStr(T t) {
290
1/1
✓ Branch 1 taken 159 times.
1/1
✓ Call 0 invoked.
318 std::ostringstream os;
291
1/1
✓ Branch 1 taken 159 times.
1/1
✓ Call 0 invoked.
318 os << t;
292
1/1
✓ Branch 1 taken 159 times.
1/1
✓ Call 0 invoked.
636 return os.str();
293
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
318 }
294
295 template <typename T>
296 inline std::string toHexStr(T t) {
297 std::ostringstream os;
298 os << std::hex << t;
299 return os.str();
300 }
301
302 template <typename T>
303 inline std::string toDecStr(T t) {
304 std::ostringstream os;
305 os << std::dec << t;
306 return os.str();
307 }
308
309 inline std::vector<std::string::size_type> strContains(const std::string& text, const std::string& word) {
310 std::vector<std::string::size_type> result;
311 std::string::size_type loc = 0;
312 while ((loc = text.find(word, loc)) != std::string::npos) {
313 result.emplace_back(loc);
314 loc += word.size();
315 }
316 return result;
317 }
318
319 8 inline bool replaceString(std::string& str, const std::string& oldStr, const std::string& newStr) {
320 8 bool found = false;
321 8 size_t pos = 0;
322
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 8 times.
1/1
✓ Call 0 invoked.
8 while ((pos = str.find(oldStr, pos)) != std::string::npos) {
323 found = true;
324
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
str.replace(pos, oldStr.length(), newStr);
325
0/1
✗ Call 0 not invoked.
pos += newStr.length();
326 }
327 8 return found;
328 }
329
330 inline size_t getCountOccurence(const std::string& vSrcString, const std::string& vStringToCount) {
331 size_t count = 0;
332 size_t pos = 0;
333 const auto len = vStringToCount.length();
334 while ((pos = vSrcString.find(vStringToCount, pos)) != std::string::npos) {
335 ++count;
336 pos += len;
337 }
338 return count;
339 }
340 inline size_t getCountOccurenceInSection(const std::string& vSrcString, size_t vStartPos, size_t vEndpos, const std::string& vStringToCount) {
341 size_t count = 0;
342 size_t pos = vStartPos;
343 const auto len = vStringToCount.length();
344 while (pos < vEndpos && (pos = vSrcString.find(vStringToCount, pos)) != std::string::npos) {
345 if (pos < vEndpos) {
346 ++count;
347 pos += len;
348 }
349 }
350 return count;
351 }
352
353 // can be more fast if char is used
354 inline size_t getCountOccurence(const std::string& vSrcString, const char& vStringToCount) {
355 size_t count = 0;
356 size_t pos = 0;
357 while ((pos = vSrcString.find(vStringToCount, pos)) != std::string::npos) {
358 ++count;
359 pos++;
360 }
361 return count;
362 }
363
364 // can be more fast if char is used
365 inline size_t getCountOccurenceInSection(const std::string& vSrcString, size_t vStartPos, size_t vEndpos, const char& vStringToCount) {
366 size_t count = 0;
367 size_t pos = vStartPos;
368 while (pos < vEndpos && (pos = vSrcString.find(vStringToCount, pos)) != std::string::npos) {
369 if (pos < vEndpos) {
370 ++count;
371 pos++;
372 }
373 }
374 return count;
375 }
376
377 // std::wstring to std::string
378 // std::wstring(unicode/multibytes/char16/wchar_t) to std::string(char)
379 inline std::string wstringToString(const std::wstring& wstr) {
380 std::mbstate_t state = std::mbstate_t();
381 const std::size_t len = wstr.size();
382 std::vector<char> mbstr(len);
383 const wchar_t* wptr = wstr.c_str();
384 #ifdef _MSC_VER
385 size_t res = 0;
386 /*errno_t err = */ wcsrtombs_s(&res, &mbstr[0], len, &wptr, mbstr.size(), &state);
387 #else
388 std::wcsrtombs(&mbstr[0], &wptr, mbstr.size(), &state);
389 #endif
390 return std::string(mbstr.data(), mbstr.size());
391 }
392
393 // std::string to std::wstring
394 // std::string(char) to std::wstring(unicode/multibytes/char16/wchar_t)
395 inline std::wstring stringToWstring(const std::string& mbstr) {
396 std::mbstate_t state = std::mbstate_t();
397 const std::size_t len = mbstr.size();
398 std::vector<wchar_t> wstr(len);
399 const char* ptr = mbstr.c_str();
400 #ifdef _MSC_VER
401 size_t res = 0;
402 /*errno_t err = */ mbsrtowcs_s(&res, &wstr[0], len, &ptr, wstr.size(), &state);
403 #else
404 std::mbsrtowcs(&wstr[0], &ptr, wstr.size(), &state);
405 #endif
406 return std::wstring(wstr.data(), wstr.size());
407 }
408
409 6 inline size_t getDigitsCountOfAIntegralNumber(const int64_t vNum) {
410
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 size_t res = (vNum == 0) ? 1 : static_cast<int>(log10(abs(vNum))) + 1;
411
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 5 times.
6 if (vNum < 0) {
412 1 ++res;
413 }
414 6 return res;
415 }
416
417 inline std::string utf8Encode(const std::wstring& wstr) {
418 std::string res;
419 #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(__WIN64__) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER)
420 if (!wstr.empty()) {
421 int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
422 if (size_needed) {
423 res = std::string(size_needed, 0);
424 WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &res[0], size_needed, NULL, NULL);
425 }
426 }
427 #else
428 // Suppress warnings from the compiler.
429 (void)wstr;
430 #endif // _IGFD_WIN_
431 return res;
432 }
433
434 // Convert an UTF8 string to a wide Unicode String
435 inline std::wstring utf8Decode(const std::string& str) {
436 std::wstring res;
437 #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(__WIN64__) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER)
438 if (!str.empty()) {
439 int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
440 if (size_needed) {
441 res = std::wstring(size_needed, 0);
442 MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &res[0], size_needed);
443 }
444 }
445 #else
446 (void)str;
447 #endif // _IGFD_WIN_
448 return res;
449 }
450
451 2 inline std::string searchForPatternWithWildcards(const std::string& vBuffer, const std::string& vWildcardedPattern, std::pair<size_t, size_t>& vOutPosRange) {
452
1/1
✓ Call 0 invoked.
2 std::string res;
453
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 auto patterns = splitStringToVector(vWildcardedPattern, '*', false);
454 2 vOutPosRange.first = std::string::npos;
455 2 vOutPosRange.second = 0U;
456
2/2
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 2 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 2 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
8 for (const std::string &pattern: patterns) {
457
1/1
✓ Call 0 invoked.
6 auto start = vBuffer.find(pattern, vOutPosRange.second);
458
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 6 times.
✗ Decision 'false' not taken.
6 if (start != std::string::npos) {
459
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 4 times.
6 if (vOutPosRange.first == std::string::npos) {
460 2 vOutPosRange.first = start;
461 }
462
1/1
✓ Call 0 invoked.
6 vOutPosRange.second = start + pattern.size();
463 } else {
464 vOutPosRange.first = std::string::npos;
465 vOutPosRange.second = std::string::npos;
466 break;
467 }
468 }
469
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2 if (vOutPosRange.first != std::string::npos && vOutPosRange.second != std::string::npos) {
470
1/1
✓ Branch 1 taken 2 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
2 res = vBuffer.substr(vOutPosRange.first, vOutPosRange.second - vOutPosRange.first);
471 }
472 4 return res;
473
1/3
✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
2 }
474
475 1 inline std::string searchForPatternWithWildcards(const std::string& vBuffer, const std::string& vWildcardedPattern) {
476 1 std::pair<size_t, size_t> posRange;
477
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
2 return searchForPatternWithWildcards(vBuffer, vWildcardedPattern, posRange);
478 }
479
480 inline std::string encodeBase64(const std::string& in) {
481 static constexpr char sEncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
482 std::string out;
483 int val = 0, valb = -6;
484 for (uint8_t c : in) {
485 val = (val << 8) + c;
486 valb += 8;
487 while (valb >= 0) {
488 out.push_back(sEncodingTable[(val >> valb) & 0x3F]);
489 valb -= 6;
490 }
491 }
492 if (valb > -6) {
493 out.push_back(sEncodingTable[((val << 8) >> (valb + 8)) & 0x3F]);
494 }
495 while (out.size() % 4) {
496 out.push_back('=');
497 }
498 return out;
499 }
500
501 // todo: to test
502 1 inline std::vector<std::string> extractWildcardsFromPattern(const std::string& vBuffer, const std::string& vPattern) {
503
1/1
✓ Call 0 invoked.
1 std::vector<std::string> res;
504
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 auto patterns = splitStringToVector(vPattern, '*', false);
505 1 std::pair<size_t, size_t> range;
506 1 range.first = std::string::npos;
507 1 range.second = 0U;
508
2/2
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
4 for (const std::string& pattern : patterns) {
509
1/1
✓ Call 0 invoked.
3 auto start = vBuffer.find(pattern, range.second);
510
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
3 if (start != std::string::npos) {
511
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
3 if (range.first != std::string::npos) {
512 2 range.second = start;
513
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
2 res.push_back(vBuffer.substr(range.first, range.second - range.first));
514 }
515
1/1
✓ Call 0 invoked.
3 range.first = start + pattern.size();
516 } else {
517 range.first = std::string::npos;
518 range.second = std::string::npos;
519 break;
520 }
521 }
522 2 return res;
523
1/3
✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
1 }
524
525 } // namespace ez
526 } // namespace ez
527
528 ////////////////////////////////////////////////////////////////////////////
529 ////////////////////////////////////////////////////////////////////////////
530 ////////////////////////////////////////////////////////////////////////////
531
532 #ifdef _MSC_VER
533 #pragma warning(pop)
534 #elif defined(__GNUC__) || defined(__clang__)
535 #pragma GCC diagnostic pop
536 #endif
537
538 ////////////////////////////////////////////////////////////////////////////
539 ////////////////////////////////////////////////////////////////////////////
540 ////////////////////////////////////////////////////////////////////////////
541

Directory: include/ezlibs/
File: ezFile.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 24 32 75.0%
Functions: 2 2 100.0%
Branches: 20 38 52.6%
Decisions: 4 12 33.3%
Calls: 30 66 45.5%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezFile is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <fstream>
30 #include <iterator>
31 #include <sstream>
32 #include <cstdint>
33 #include <string>
34 #include <vector>
35 #include <ctime>
36
37 #include "ezStr.hpp"
38 #include "ezLog.hpp"
39 #include <sys/stat.h>
40
41 #ifndef EZ_FILE_SLASH_TYPE
42 #ifdef WIN32
43 #define EZ_FILE_SLASH_TYPE "\\"
44 #include <Windows.h>
45 #include <shellapi.h> // ShellExecute
46 #define stat _stat
47 #else // UNIX
48 #define EZ_FILE_SLASH_TYPE "/"
49 #endif
50 #endif // EZ_FILE_SLASH_TYPE
51
52 namespace ez {
53 namespace file {
54
55 4 inline std::string loadFileToString(const std::string &vFilePathName, bool vVerbose = true) {
56
1/1
✓ Call 0 invoked.
4 std::string ret;
57
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::ifstream docFile(vFilePathName, std::ios::in);
58
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (docFile.is_open()) {
59
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::stringstream strStream;
60
1/1
✓ Branch 2 taken 4 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
4 strStream << docFile.rdbuf(); // read the file
61
1/1
✓ Branch 1 taken 4 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
4 ret = strStream.str();
62
3/3
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
16 ez::str::replaceString(ret, "\r\n", "\n");
63
3/3
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
12 ez::str::replaceString(ret, "\r", "\n");
64
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 docFile.close();
65
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
4 } else {
66
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (vVerbose) {
67 #ifdef EZ_TOOLS_LOG
68
0/6
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
LogVarError("File \"%s\" Not Found !\n", vFilePathName.c_str());
69 #endif
70 }
71 }
72 8 return ret;
73
1/3
✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
4 }
74
75 1 inline bool saveStringToFile(const std::string &vDatas, const std::string &vFilePathName, bool vAddTimeStamp = false) {
76
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 std::string fpn = vFilePathName;
77
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (!fpn.empty()) {
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (vAddTimeStamp) {
79
0/1
✗ Call 0 not invoked.
auto dot_p = fpn.find_last_of('.');
80
0/1
✗ Call 0 not invoked.
time_t epoch = std::time(nullptr);
81
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (dot_p != std::string::npos) {
82
0/15
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 9 not invoked.
✗ Call 12 not invoked.
✗ Call 15 not invoked.
✗ Call 16 not invoked.
✗ Call 17 not invoked.
✗ Call 18 not invoked.
✗ Call 19 not invoked.
✗ Call 20 not invoked.
✗ Call 21 not invoked.
✗ Call 22 not invoked.
✗ Call 23 not invoked.
✗ Call 24 not invoked.
fpn = fpn.substr(0, dot_p) + ez::str::toStr("_%llu", epoch) + fpn.substr(dot_p);
83 } else {
84
0/4
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
fpn += ez::str::toStr("_%llu", epoch);
85 }
86 }
87
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 std::ofstream configFileWriter(fpn, std::ios::out);
88
2/3
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (!configFileWriter.bad()) {
89
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 configFileWriter << vDatas;
90
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 configFileWriter.close();
91 1 return true;
92 }
93
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
1 }
94 return false;
95
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
1 }
96
97 inline std::vector<uint8_t> loadFileToBin(const std::string &vFilePathName) {
98 std::vector<uint8_t> ret;
99 std::ifstream docFile(vFilePathName, std::ios::in | std::ios::binary);
100 if (docFile.is_open()) {
101 // int32_t because the internal << used by 'istream_iterator' is not defined for uint8_t
102 ret = {std::istream_iterator<char>(docFile), std::istream_iterator<char>()};
103 docFile.close();
104 } else {
105 #ifdef EZ_TOOLS_LOG
106 LogVarError("File \"%s\" Not Found !\n", vFilePathName.c_str());
107 #endif
108 }
109 return ret;
110 }
111
112 inline bool saveBinToFile(const std::vector<uint8_t> &vDatas, const std::string &vFilePathName, bool vAddTimeStamp = false) {
113 std::string fpn = vFilePathName;
114 if (!fpn.empty()) {
115 if (vAddTimeStamp) {
116 auto dot_p = fpn.find_last_of('.');
117 time_t epoch = std::time(nullptr);
118 if (dot_p != std::string::npos) {
119 fpn = fpn.substr(0, dot_p) + ez::str::toStr("_%llu", epoch) + fpn.substr(dot_p);
120 } else {
121 fpn += ez::str::toStr("_%llu", epoch);
122 }
123 }
124 std::ofstream out(fpn, std::ios::out | std::ios::binary);
125 if (!out.bad()) {
126 out.write(reinterpret_cast<const char *>(vDatas.data()), vDatas.size());
127 out.close();
128 return true;
129 }
130 }
131 return false;
132 }
133
134 /* correct file path between os and different slash type between window and unix */
135 inline std::string correctSlashTypeForFilePathName(const std::string &vFilePathName) {
136 std::string res = vFilePathName;
137 ez::str::replaceString(res, "\\", EZ_FILE_SLASH_TYPE);
138 ez::str::replaceString(res, "/", EZ_FILE_SLASH_TYPE);
139 return res;
140 }
141
142 struct PathInfos {
143 std::string path;
144 std::string name;
145 std::string ext;
146 bool isOk = false;
147
148 PathInfos() {
149 isOk = false;
150 }
151
152 PathInfos(const std::string &vPath, const std::string &vName, const std::string &vExt) {
153 isOk = true;
154 path = vPath;
155 name = vName;
156 ext = vExt;
157
158 if (ext.empty()) {
159 const size_t lastPoint = name.find_last_of('.');
160 if (lastPoint != std::string::npos) {
161 ext = name.substr(lastPoint + 1);
162 name = name.substr(0, lastPoint);
163 }
164 }
165 }
166
167 std::string GetFPNE() {
168 return GetFPNE_WithPathNameExt(path, name, ext);
169 }
170
171 std::string GetFPNE_WithPathNameExt(std::string vPath, const std::string &vName, const std::string &vExt) {
172 if (vPath[0] == EZ_FILE_SLASH_TYPE[0]) {
173 #ifdef WIN32
174 // if it happening on window this seem that this path msut be a relative path but with an error
175 vPath = vPath.substr(1); // bad formated path go relative
176 #endif
177 } else {
178 #ifdef UNIX
179 vPath = "/" + vPath; // make it absolute
180 #endif
181 }
182
183 if (vPath.empty()) return vName + "." + vExt;
184
185 return vPath + EZ_FILE_SLASH_TYPE + vName + "." + vExt;
186 }
187
188 std::string GetFPNE_WithPath(const std::string &vPath) {
189 return GetFPNE_WithPathNameExt(vPath, name, ext);
190 }
191
192 std::string GetFPNE_WithPathName(const std::string &vPath, const std::string &vName) {
193 return GetFPNE_WithPathNameExt(vPath, vName, ext);
194 }
195
196 std::string GetFPNE_WithPathExt(const std::string &vPath, const std::string &vExt) {
197 return GetFPNE_WithPathNameExt(vPath, name, vExt);
198 }
199
200 std::string GetFPNE_WithName(const std::string &vName) {
201 return GetFPNE_WithPathNameExt(path, vName, ext);
202 }
203
204 std::string GetFPNE_WithNameExt(const std::string &vName, const std::string &vExt) {
205 return GetFPNE_WithPathNameExt(path, vName, vExt);
206 }
207
208 std::string GetFPNE_WithExt(const std::string &vExt) {
209 return GetFPNE_WithPathNameExt(path, name, vExt);
210 }
211 };
212
213 inline PathInfos parsePathFileName(const std::string &vPathFileName) {
214 PathInfos res;
215 if (!vPathFileName.empty()) {
216 const std::string pfn = correctSlashTypeForFilePathName(vPathFileName);
217 if (!pfn.empty()) {
218 const size_t lastSlash = pfn.find_last_of(EZ_FILE_SLASH_TYPE);
219 if (lastSlash != std::string::npos) {
220 res.name = pfn.substr(lastSlash + 1);
221 res.path = pfn.substr(0, lastSlash);
222 res.isOk = true;
223 }
224 const size_t lastPoint = pfn.find_last_of('.');
225 if (lastPoint != std::string::npos) {
226 if (!res.isOk) {
227 res.name = pfn;
228 res.isOk = true;
229 }
230 res.ext = pfn.substr(lastPoint + 1);
231 ez::str::replaceString(res.name, "." + res.ext, "");
232 }
233 if (!res.isOk) {
234 res.name = pfn;
235 res.isOk = true;
236 }
237 }
238 }
239 return res;
240 }
241
242 inline std::string simplifyFilePath(const std::string &vFilePath) {
243 std::string newPath = correctSlashTypeForFilePathName(vFilePath);
244 // the idea is to simplify a path where there is some ..
245 // by ex : script\\kifs\\../space3d.glsl => can be simplified in /script/space3d.glsl
246 size_t dpt = 0;
247 while ((dpt = newPath.find("..")) != std::string::npos) {
248 ez::str::replaceString(newPath, "\\", EZ_FILE_SLASH_TYPE);
249 ez::str::replaceString(newPath, "/", EZ_FILE_SLASH_TYPE);
250 size_t sl = newPath.rfind(EZ_FILE_SLASH_TYPE, dpt);
251 if (sl != std::string::npos) {
252 if (sl > 0) {
253 sl = newPath.rfind(EZ_FILE_SLASH_TYPE, sl - 1);
254 if (sl != std::string::npos) {
255 std::string str = newPath.substr(sl, dpt + 2 - sl);
256 ez::str::replaceString(newPath, str, "");
257 }
258 }
259 } else {
260 break;
261 }
262 }
263 return newPath;
264 }
265
266 inline std::string composePath(const std::string &vPath, const std::string &vFileName, const std::string &vExt) {
267 const auto path = correctSlashTypeForFilePathName(vPath);
268 std::string res = path;
269 if (!vFileName.empty()) {
270 if (!path.empty()) {
271 res += EZ_FILE_SLASH_TYPE;
272 }
273 res += vFileName;
274 if (!vExt.empty()) {
275 res += "." + vExt;
276 }
277 }
278 return res;
279 }
280
281 inline bool isFileExist(const std::string &name) {
282 auto fileToOpen = correctSlashTypeForFilePathName(name);
283 ez::str::replaceString(fileToOpen, "\"", "");
284 ez::str::replaceString(fileToOpen, "\n", "");
285 ez::str::replaceString(fileToOpen, "\r", "");
286 std::ifstream docFile(fileToOpen, std::ios::in);
287 if (docFile.is_open()) {
288 docFile.close();
289 return true;
290 }
291 return false;
292 }
293
294 inline bool isDirectoryExist(const std::string &name) {
295 if (!name.empty()) {
296 const std::string dir = correctSlashTypeForFilePathName(name);
297 struct stat sb;
298 if (stat(dir.c_str(), &sb)) {
299 return (sb.st_mode & S_IFDIR);
300 }
301 }
302 return false;
303 }
304
305 inline bool destroyFile(const std::string &vFilePathName) {
306 if (!vFilePathName.empty()) {
307 const auto filePathName = correctSlashTypeForFilePathName(vFilePathName);
308 if (isFileExist(filePathName)) {
309 if (remove(filePathName.c_str()) == 0) {
310 return true;
311 }
312 }
313 }
314 return false;
315 }
316
317 inline bool createDirectoryIfNotExist(const std::string &name) {
318 bool res = false;
319 if (!name.empty()) {
320 const auto filePathName = correctSlashTypeForFilePathName(name);
321 if (!isDirectoryExist(filePathName)) {
322 res = true;
323 #ifdef WIN32
324 CreateDirectory(filePathName.c_str(), nullptr);
325 #elif defined(UNIX)
326 auto cmd = ez::str::toStr("mkdir -p %s", filePathName.c_str());
327 const int dir_err = std::system(cmd.c_str());
328 if (dir_err == -1) {
329 LogVarError("Error creating directory %s", filePathName.c_str());
330 res = false;
331 }
332 #endif
333 }
334 }
335 return res;
336 }
337
338 inline bool createPathIfNotExist(const std::string &vPath) {
339 bool res = false;
340 if (!vPath.empty()) {
341 auto path = correctSlashTypeForFilePathName(vPath);
342 if (!isDirectoryExist(path)) {
343 res = true;
344 ez::str::replaceString(path, "/", "|");
345 ez::str::replaceString(path, "\\", "|");
346 auto arr = ez::str::splitStringToVector(path, "|");
347 std::string fullPath;
348 for (auto it = arr.begin(); it != arr.end(); ++it) {
349 fullPath += *it;
350 res &= createDirectoryIfNotExist(fullPath);
351 fullPath += EZ_FILE_SLASH_TYPE;
352 }
353 }
354 }
355 return res;
356 }
357
358 // will open the file is the associated app
359 inline void openFile(const std::string &vFile) {
360 const auto file = correctSlashTypeForFilePathName(vFile);
361 #if defined(WIN32)
362 auto *result = ShellExecute(nullptr, "", file.c_str(), nullptr, nullptr, SW_SHOW);
363 if (result < (HINSTANCE)32) { //-V112
364 // try to open an editor
365 result = ShellExecute(nullptr, "edit", file.c_str(), nullptr, nullptr, SW_SHOW);
366 if (result == (HINSTANCE)SE_ERR_ASSOCINCOMPLETE || result == (HINSTANCE)SE_ERR_NOASSOC) {
367 // open associating dialog
368 const std::string sCmdOpenWith = "shell32.dll,OpenAs_RunDLL \"" + file + "\"";
369 result = ShellExecute(nullptr, "", "rundll32.exe", sCmdOpenWith.c_str(), nullptr, SW_NORMAL);
370 }
371 if (result < (HINSTANCE)32) { // open in explorer //-V112
372 const std::string sCmdExplorer = "/select,\"" + file + "\"";
373 ShellExecute(
374 nullptr, "", "explorer.exe", sCmdExplorer.c_str(), nullptr, SW_NORMAL); // ce serait peut etre mieu d'utilsier la commande system comme dans SelectFile
375 }
376 }
377 #elif defined(LINUX)
378 int pid = fork();
379 if (pid == 0) {
380 execl("/usr/bin/xdg-open", "xdg-open", file.c_str(), (char *)0);
381 }
382 #elif defined(APPLE)
383 std::string cmd = "open " + file;
384 std::system(cmd.c_str());
385 #endif
386 }
387
388 // will open the url in the related browser
389 inline void openUrl(const std::string &vUrl) {
390 const auto url = correctSlashTypeForFilePathName(vUrl);
391 #ifdef WIN32
392 ShellExecute(nullptr, nullptr, url.c_str(), nullptr, nullptr, SW_SHOW);
393 #elif defined(LINUX)
394 auto cmd = ez::str::toStr("<mybrowser> %s", url.c_str());
395 std::system(cmd.c_str());
396 #elif defined(APPLE)
397 // std::string sCmdOpenWith = "open -a Firefox " + vUrl;
398 std::string cmd = "open " + url;
399 std::system(cmd.c_str());
400 #endif
401 }
402
403 // will open the current file explorer and will select the file
404 inline void selectFile(const std::string &vFileToSelect) {
405 const auto fileToSelect = correctSlashTypeForFilePathName(vFileToSelect);
406 #ifdef WIN32
407 if (!fileToSelect.empty()) {
408 const std::string sCmdOpenWith = "explorer /select," + fileToSelect;
409 std::system(sCmdOpenWith.c_str());
410 }
411 #elif defined(LINUX)
412 // todo : is there a similar cmd on linux ?
413 assert(nullptr);
414 #elif defined(APPLE)
415 if (!fileToSelect.empty()) {
416 std::string cmd = "open -R " + fileToSelect;
417 std::system(cmd.c_str());
418 }
419 #endif
420 }
421
422 inline std::vector<std::string> getDrives() {
423 std::vector<std::string> res;
424 #ifdef WIN32
425 const DWORD mydrives = 2048;
426 char lpBuffer[2048 + 1];
427 const DWORD countChars = GetLogicalDriveStrings(mydrives, lpBuffer);
428 if (countChars > 0) {
429 std::string var = std::string(lpBuffer, (size_t)countChars);
430 ez::str::replaceString(var, "\\", "");
431 res = ez::str::splitStringToVector(var, "\0");
432 }
433 #else
434 assert(nullptr);
435 #endif
436 return res;
437 }
438
439 } // namespace file
440 } // namespace ez
441

Directory: include/ezlibs/
File: ezLog.hpp
Date: 2025-07-28 14:06:36
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 58 76 76.3%
Functions: 8 9 88.9%
Branches: 38 67 56.7%
Decisions: 11 24 45.8%
Calls: 48 68 70.6%
Line Branch Decision Call Exec Source
1 /*
2 MIT License
3
4 Copyright (c) 2010-2020 Stephane Cuillerdier (aka Aiekick)
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24
25 // ezLog is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
26 // ezLog is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
27
28 #pragma once
29 #pragma warning(disable : 4251)
30
31 #ifndef EZ_TOOLS_LOG
32 #define EZ_TOOLS_LOG
33 #endif // EZ_TOOLS_LOG
34
35 #ifndef EZ_LOG_APP_NAME
36 #define EZ_LOG_APP_NAME "App"
37 #endif
38
39 #include "ezStr.hpp"
40 #include "ezTime.hpp"
41
42 #ifdef USE_GLFW3
43 #include <GLFW/glfw3.h>
44 #elif defined(USE_SDL2)
45 #include <SDL.h>
46 #endif
47 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
48 #include <tracy/Tracy.hpp>
49 #endif
50
51 #ifdef _MSC_VER
52 #include <Windows.h>
53 #endif
54
55 #include <cstdarg> /* va_list, va_start, va_arg, va_end */
56
57 #include <iostream> // std::cout
58
59 #include <mutex>
60 #include <string>
61 #include <vector>
62 #include <memory>
63 #include <cassert>
64 #include <fstream>
65 #include <stdexcept>
66 #include <functional>
67 using namespace std;
68
69 typedef long long int64;
70
71 #ifdef _MSC_VER
72 #define __PRETTY_FUNCTION__ __FUNCSIG__
73 #endif
74
75 #ifdef __ANDROID__
76 #include <android/log.h>
77 #endif
78
79 #define IsVerboseMode (ez::Log::Instance()->isVerboseMode() == true)
80
81 // #define LogVar(s, ...) ez::Log::Instance()->logStringWithFunction(std::string(__FUNCTION__), (int)(__LINE__), s,
82 // ##__VA_ARGS__)
83
84 #define LogVarError(s, ...) \
85 ez::Log::Instance()->logStringByTypeWithFunction(ez::Log::LOGGING_MESSAGE_TYPE_ERROR, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__)
86
87 #define LogVarWarning(s, ...) \
88 ez::Log::Instance()->logStringByTypeWithFunction(ez::Log::LOGGING_MESSAGE_TYPE_WARNING, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__)
89
90 #define LogVarInfo(s, ...) \
91 ez::Log::Instance()->logStringByTypeWithFunction(ez::Log::LOGGING_MESSAGE_TYPE_INFOS, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__)
92
93 #define LogVarDebugError(s, ...) \
94 ez::Log::Instance()->logStringByTypeWithFunction_Debug(ez::Log::LOGGING_MESSAGE_TYPE_ERROR, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__)
95
96 #define LogVarDebugWarning(s, ...) \
97 ez::Log::Instance()->logStringByTypeWithFunction_Debug(ez::Log::LOGGING_MESSAGE_TYPE_WARNING, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__)
98
99 #define LogVarDebugInfo(s, ...) \
100 ez::Log::Instance()->logStringByTypeWithFunction_Debug(ez::Log::LOGGING_MESSAGE_TYPE_INFOS, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__)
101
102 #define LogVarLightError(s, ...) ez::Log::Instance()->logSimpleStringByType(ez::Log::LOGGING_MESSAGE_TYPE_ERROR, s, ##__VA_ARGS__)
103
104 #define LogVarLightWarning(s, ...) ez::Log::Instance()->logSimpleStringByType(ez::Log::LOGGING_MESSAGE_TYPE_WARNING, s, ##__VA_ARGS__)
105
106 #define LogVarLightInfo(s, ...) ez::Log::Instance()->logSimpleStringByType(ez::Log::LOGGING_MESSAGE_TYPE_INFOS, s, ##__VA_ARGS__)
107
108 #define LogVarTag(t, s, ...) ez::Log::Instance()->logStringByTypeWithFunction(t, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__)
109
110 #define LogVarLightTag(t, s, ...) ez::Log::Instance()->logSimpleStringByType(t, s, ##__VA_ARGS__)
111
112 #define LogAssert(a, b, ...) \
113 if (!(a)) { \
114 LogVarDebugInfo(b, ##__VA_ARGS__); \
115 assert(a); \
116 }
117
118 #ifdef USE_OPENGL
119 #define LogGlError() ez::Log::Instance()->logGLError("" /*__FILE__*/, __FUNCTION__, __LINE__, "")
120 #define LogGlErrorVar(var) ez::Log::Instance()->logGLError("" /*__FILE__*/, __FUNCTION__, __LINE__, var)
121 #endif
122
123 namespace ez {
124
125 class Log {
126 public:
127 typedef int MessageType;
128 typedef std::function<void(const int& vType, const std::string& vMessage)> LogMessageFunctor;
129 enum MessageTypeEnum { LOGGING_MESSAGE_TYPE_INFOS = 0, LOGGING_MESSAGE_TYPE_WARNING, LOGGING_MESSAGE_TYPE_ERROR };
130
131 protected:
132 std::mutex m_logger_Mutex;
133
134 private:
135 static size_t constexpr sMAX_BUFFER_SIZE = 1024U * 3U;
136 ofstream m_debugLogFile;
137 int64 m_lastTick = 0;
138 bool m_reseted = false;
139 LogMessageFunctor m_standardLogFunction;
140 LogMessageFunctor m_openGLLogFunction;
141 std::vector<std::string> m_messages; // file, function, line, msg
142 bool m_consoleVerbose = false;
143
144 public:
145
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
58 Log() {
146 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
147 ZoneScoped;
148 #endif
149 58 }
150 58 ~Log() {
151 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
152 ZoneScoped;
153 #endif
154
1/1
✓ Call 0 invoked.
58 close();
155
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
58 }
156 void logSimpleString(const char* fmt, ...) {
157 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
158 ZoneScoped;
159 #endif
160 std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
161 lck.lock();
162 va_list args;
163 va_start(args, fmt);
164 m_LogString(nullptr, nullptr, nullptr, fmt, args);
165 va_end(args);
166 lck.unlock();
167 }
168 void logSimpleStringByType(const MessageType& vType, const char* fmt, ...) {
169 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
170 ZoneScoped;
171 #endif
172
0/1
✗ Call 0 not invoked.
std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
173
0/1
✗ Call 0 not invoked.
lck.lock();
174 va_list args;
175 va_start(args, fmt);
176
0/1
✗ Call 0 not invoked.
m_LogString(&vType, nullptr, nullptr, fmt, args);
177 va_end(args);
178
0/1
✗ Call 0 not invoked.
lck.unlock();
179 }
180 void logStringWithFunction(const std::string& vFunction, const int& vLine, const char* fmt, ...) {
181 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
182 ZoneScoped;
183 #endif
184 std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
185 lck.lock();
186 va_list args;
187 va_start(args, fmt);
188 m_LogString(nullptr, &vFunction, &vLine, fmt, args);
189 va_end(args);
190 lck.unlock();
191 }
192 80 void logStringByTypeWithFunction(const MessageType& vType, const std::string& vFunction, const int& vLine, const char* fmt, ...) {
193 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
194 ZoneScoped;
195 #endif
196
1/1
✓ Call 0 invoked.
80 std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
197
1/1
✓ Branch 1 taken 80 times.
1/1
✓ Call 0 invoked.
80 lck.lock();
198 va_list args;
199 80 va_start(args, fmt);
200
1/1
✓ Branch 1 taken 80 times.
1/1
✓ Call 0 invoked.
80 m_LogString(&vType, &vFunction, &vLine, fmt, args);
201 80 va_end(args);
202
1/1
✓ Branch 1 taken 80 times.
1/1
✓ Call 0 invoked.
80 lck.unlock();
203
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
80 }
204 void logStringByTypeWithFunction_Debug(const MessageType& vType, const std::string& vFunction, const int& vLine, const char* fmt, ...) {
205 #ifdef _DEBUG
206 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
207 ZoneScoped;
208 #endif
209 std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
210 lck.lock();
211 va_list args;
212 va_start(args, fmt);
213 m_LogString(&vType, &vFunction, &vLine, fmt, args);
214 va_end(args);
215 lck.unlock();
216 #else
217 (void)vType;
218 (void)vFunction;
219 (void)vLine;
220 (void)fmt;
221 #endif
222 }
223 void logStringWithFunction_Debug(const std::string& vFunction, const int& vLine, const char* fmt, ...) {
224 #ifdef _DEBUG
225 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
226 ZoneScoped;
227 #endif
228 std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
229 lck.lock();
230 va_list args;
231 va_start(args, fmt);
232 m_LogString(nullptr, &vFunction, &vLine, fmt, args);
233 va_end(args);
234 lck.unlock();
235 #else
236 (void)vFunction;
237 (void)vLine;
238 (void)fmt;
239 #endif
240 }
241 #ifdef USE_OPENGL
242 bool logGLError(const std::string& vFile, const std::string& vFunc, int vLine, const std::string& vGLFunc = "") const {
243 (void)vFile;
244
245 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
246 ZoneScoped;
247 #endif
248 if (!ez::Log::Instance()->ConsoleVerbose)
249 return false;
250
251 const GLenum err(glGetError());
252 if (err != GL_NO_ERROR) {
253 std::string error;
254
255 switch (err) {
256 case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break;
257 case GL_INVALID_ENUM: error = "INVALID_ENUM"; break;
258 case GL_INVALID_VALUE: error = "INVALID_VALUE"; break;
259 case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break;
260 case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
261 case GL_STACK_UNDERFLOW: error = "GL_STACK_UNDERFLOW"; break;
262 case GL_STACK_OVERFLOW: error = "GL_STACK_OVERFLOW"; break;
263 }
264
265 if (!error.empty()) {
266 const int64 ticks = ez::time::GetTicks();
267 const float time = (ticks - m_lastTick) / 1000.0f;
268
269 std::string msg;
270
271 if (!vGLFunc.empty()) {
272 #ifdef USE_GLFW3
273 msg = str::toStr(
274 "[%010.3fs][GLFW3 0x%X][%s:%i] %s in %s\n", time, (uintptr_t)glfwGetCurrentContext(), vFunc.c_str(), vLine, error.c_str(), vGLFunc.c_str());
275 #elif defined(USE_SDL2)
276 msg = str::toStr(
277 "[%010.3fs][SDL2 0x%X][%s:%i] %s in %s\n", time, (uintptr_t)SDL_GL_GetCurrentContext(), vFunc.c_str(), vLine, error.c_str(), vGLFunc.c_str());
278 #endif
279 } else {
280 #ifdef USE_GLFW3
281 msg = str::toStr("[%010.3fs][GLFW3 0x%X][%s:%i] %s\n", time, (uintptr_t)glfwGetCurrentContext(), vFunc.c_str(), vLine, error.c_str());
282 #elif defined(USE_SDL2)
283 msg = str::toStr("[%010.3fs][SDL2 0x%X][%s:%i] %s\n", time, (uintptr_t)SDL_GL_GetCurrentContext(), vFunc.c_str(), vLine, error.c_str());
284 #endif
285 }
286
287 LogVarLightError("%s", msg.c_str());
288
289 if (m_openGLLogFunction != nullptr) {
290 auto arr = str::splitStringToVector(msg, '\n');
291 if (arr.size() == 1U) {
292 m_openGLLogFunction(2, msg);
293 } else {
294 for (auto m : arr) {
295 m_openGLLogFunction(2, m);
296 }
297 }
298 }
299
300 if (!m_debugLogFile.bad())
301 m_debugLogFile << msg << std::endl;
302
303 return true;
304 }
305 }
306
307 return false;
308 }
309 #endif
310 58 void close() {
311 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
312 ZoneScoped;
313 #endif
314
1/1
✓ Call 0 invoked.
58 std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
315
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 lck.lock();
316
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 m_debugLogFile.close();
317
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 m_debugLogFile.clear();
318
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 lck.unlock();
319
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
58 }
320
321 std::string getLastErrorAsString() {
322 std::string msg;
323
324 #ifdef _MSC_VER
325 // Get the error message, if any.
326 const DWORD errorMessageID = ::GetLastError();
327 if (errorMessageID == 0 || errorMessageID == 6)
328 return std::string(); // No error message has been recorded
329
330 LPSTR messageBuffer = nullptr;
331 const size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
332 nullptr,
333 errorMessageID,
334 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
335 (LPSTR)&messageBuffer,
336 0,
337 nullptr);
338
339 msg = std::string(messageBuffer, size);
340
341 // Free the buffer.
342 LocalFree(messageBuffer);
343 #else
344 // cAssert(0, "to implement");
345 #endif
346 return msg;
347 }
348
349 void setStandardLogMessageFunctor(const LogMessageFunctor& vMessageLogFunctor) { m_standardLogFunction = vMessageLogFunctor; }
350 void setOpenglLogMessageFunctor(const LogMessageFunctor& vMessageLogFunctor) { m_openGLLogFunction = vMessageLogFunctor; }
351
352 void setVerboseMode(bool vFlag) { m_consoleVerbose = vFlag; }
353 bool isVerboseMode() { return m_consoleVerbose; }
354
355 private:
356 80 void m_createFileOnDisk() {
357
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 58 times.
2/2
✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 58 times.
80 if (m_reseted) {
358 22 return;
359 }
360 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
361 ZoneScoped;
362 #endif
363
1/1
✓ Call 0 invoked.
58 std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock);
364
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 lck.lock();
365
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 m_debugLogFile.open("debug.log", ios::out);
366
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 m_lastTick = time::getTicks();
367 58 m_consoleVerbose = false;
368 58 m_reseted = true;
369
1/1
✓ Branch 1 taken 58 times.
1/1
✓ Call 0 invoked.
58 lck.unlock();
370
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
58 }
371
372 private:
373 69 void m_LogString(const MessageType* vType, const std::string* vFunction, const int* vLine, const char* vStr) {
374
1/1
✓ Call 0 invoked.
69 const int64 ticks = time::getTicks();
375 69 const double time = (ticks - m_lastTick) / 1000.0;
376
377 static char TempBufferBis[sMAX_BUFFER_SIZE + 1];
378 69 int w = 0;
379
2/4
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 69 times.
✗ Decision 'false' not taken.
69 if (vFunction && vLine)
380
1/1
✓ Call 0 invoked.
69 w = snprintf(TempBufferBis, sMAX_BUFFER_SIZE, "[%010.3fs][%s:%i] %s", time, vFunction->c_str(), *vLine, vStr);
381 else
382 w = snprintf(TempBufferBis, sMAX_BUFFER_SIZE, "[%010.3fs] %s", time, vStr);
383
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 69 times.
✗ Decision 'false' not taken.
69 if (w) {
384
1/1
✓ Branch 1 taken 69 times.
1/1
✓ Call 0 invoked.
69 const std::string msg = std::string(TempBufferBis, (size_t)w);
385
386
1/1
✓ Branch 1 taken 69 times.
1/1
✓ Call 0 invoked.
69 m_messages.push_back(msg);
387
388 #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES)
389 TracyMessageL(m_messages[m_messages.size() - 1U].c_str());
390 #endif
391
392 #ifdef __ANDROID__
393 if (*vType == MessageTypeEnum::LOGGING_MESSAGE_TYPE_INFOS) {
394 __android_log_write(ANDROID_LOG_INFO, EZ_LOG_APP_NAME, msg.c_str());
395 } else if (*vType == MessageTypeEnum::LOGGING_MESSAGE_TYPE_WARNING) {
396 __android_log_write(ANDROID_LOG_WARN, EZ_LOG_APP_NAME, msg.c_str());
397 } else if (*vType == MessageTypeEnum::LOGGING_MESSAGE_TYPE_ERROR) {
398 __android_log_write(ANDROID_LOG_ERROR, EZ_LOG_APP_NAME, msg.c_str());
399 }
400 #else
401
2/2
✓ Branch 1 taken 69 times.
✓ Branch 4 taken 69 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
69 std::cout << msg << std::endl;
402 #endif
403
404
405
3/6
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 69 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 69 times.
1/1
✓ Call 2 invoked.
69 if (vStr && m_standardLogFunction) {
406 int type = 0;
407
408
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (vType) {
409 type = (int)(*vType);
410 }
411
412
0/1
✗ Call 0 not invoked.
auto arr = str::splitStringToVector(msg, '\n');
413
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/1
✗ Call 0 not invoked.
if (arr.size() == 1U) {
414
0/1
✗ Call 0 not invoked.
m_standardLogFunction(type, msg);
415 } else {
416
0/1
? Decision couldn't be analyzed.
0/6
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
for (auto m : arr) {
417
0/1
✗ Call 0 not invoked.
m_standardLogFunction(type, m);
418 }
419 }
420 }
421
422
2/3
✓ Branch 1 taken 69 times.
✓ Branch 3 taken 69 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 69 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
69 if (!m_debugLogFile.bad())
423
2/2
✓ Branch 1 taken 69 times.
✓ Branch 4 taken 69 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
69 m_debugLogFile << msg << std::endl;
424
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
69 }
425 69 }
426 80 void m_LogString(const MessageType* vType, const std::string* vFunction, const int* vLine, const char* fmt, va_list vArgs) {
427 static char TempBuffer[sMAX_BUFFER_SIZE + 1];
428 80 int w = vsnprintf(TempBuffer, sMAX_BUFFER_SIZE, fmt, vArgs);
429
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 11 times.
2/2
✓ Decision 'true' taken 69 times.
✓ Decision 'false' taken 11 times.
80 if (w) {
430
1/1
✓ Call 0 invoked.
69 m_LogString(vType, vFunction, vLine, TempBuffer);
431 }
432 80 }
433
434 public:
435 80 static ez::Log* Instance(ez::Log* vCopyPtr = nullptr, bool vForce = false) {
436
5/10
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 22 times.
✓ Branch 3 taken 58 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 58 times.
✓ Branch 9 taken 58 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
6/8
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✓ Call 11 invoked.
✓ Call 12 invoked.
✓ Call 13 invoked.
✗ Call 16 not invoked.
✗ Call 19 not invoked.
80 static auto instance_ptr = std::unique_ptr<ez::Log>(new ez::Log()); // std::make_unique is not available in cpp11
437 static ez::Log* _instance_copy = nullptr;
438
2/4
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 80 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 80 times.
80 if (vCopyPtr || vForce) {
439 _instance_copy = vCopyPtr;
440
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 80 times.
✗ Decision 'false' not taken.
80 } else if (_instance_copy == nullptr) {
441
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
80 instance_ptr->m_createFileOnDisk();
442 }
443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 80 times.
80 if (_instance_copy) {
444 return _instance_copy;
445 }
446
1/1
✓ Call 0 invoked.
80 return instance_ptr.get();
447 }
448 };
449
450 } // namespace ez
451

Directory: include/ezlibs/
File: ezBuildInc.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 131 135 97.0%
Functions: 18 18 100.0%
Branches: 155 168 92.3%
Decisions: 35 46 76.1%
Calls: 204 241 84.6%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezBuildInc is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <string>
30 #include <cstdint>
31 #include <fstream>
32 #include <sstream>
33 #include <iostream>
34
35 // you msut include ezFigFont.hpp before this include
36 // if you want to enable the FigFont Label Generation
37
38 namespace ez {
39
40 /* File Format
41 #pragma once
42
43 #define Project_Label "project"
44 #define Project_BuildNumber 3629
45 #define Project_MinorNumber 3
46 #define Project_MajorNumber 0
47 #define Project_BuildId "0.3.3629"
48 #define Project_FigFontLabel "..." // Optionnal
49 */
50
51 class BuildInc {
52 private:
53 bool m_lastWriteStatus = false;
54 std::string m_buildFileHeader;
55 std::string m_project;
56 std::string m_label;
57 int32_t m_majorNumber = 0;
58 int32_t m_minorNumber = 0;
59 int32_t m_buildNumber = 0;
60 #ifdef EZ_FIG_FONT
61 class FigFontGenerator {
62 friend class BuildInc;
63 private:
64 ez::FigFont m_generator;
65 bool m_useLabel = true; // will use the label or not for the FigFont label
66 bool m_useBuildNumber = false; // will use the buildNumber or not for the FigFont label
67 public:
68
1/1
✓ Call 0 invoked.
6 bool isValid() { return m_generator.isValid(); }
69 2 FigFontGenerator& useLabel(const bool vFlag) {
70 2 m_useLabel = vFlag;
71 2 return *this;
72 }
73 2 FigFontGenerator& useBuildNumber(const bool vFlag) {
74 2 m_useBuildNumber = vFlag;
75 2 return *this;
76 }
77 } m_figFontGenerator;
78 #endif // EZ_FIG_FONT
79
80 public:
81
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
1 BuildInc(const std::string& vBuildFileHeader) {
82
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 m_buildFileHeader = vBuildFileHeader;
83
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 read();
84
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
1 }
85 1 BuildInc& read() {
86
1/1
✓ Call 0 invoked.
1 std::string content;
87
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 std::ifstream docFile(m_buildFileHeader, std::ios::in);
88
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (docFile.is_open()) {
89
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 std::stringstream strStream;
90
1/1
✓ Branch 2 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 strStream << docFile.rdbuf();
91
1/1
✓ Branch 1 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
1 content = strStream.str();
92
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 docFile.close();
93
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
1 }
94
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (!content.empty()) {
95 1 size_t startLine = 0;
96
1/1
✓ Call 0 invoked.
1 size_t endLine = content.find('\n', startLine);
97
1/1
✓ Call 0 invoked.
1 std::string line;
98
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 std::string project, key, value;
99
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 1 times.
9 while (endLine != std::string::npos) {
100
1/1
✓ Branch 1 taken 8 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
8 line = content.substr(startLine, endLine - startLine);
101
3/3
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 3 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
8 if (m_parseDefine(line, project, key, value)) {
102
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 m_project = project; // overwrote each time but its the same for each
103
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
5 if (key == "Label") {
104
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 m_label = value;
105
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
4 } else if (key == "MajorNumber") {
106
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 m_majorNumber = m_toNumber(value);
107
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
3 } else if (key == "MinorNumber") {
108
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 m_minorNumber = m_toNumber(value);
109
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
1/1
✓ Call 0 invoked.
2 } else if (key == "BuildNumber") {
110
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 m_buildNumber = m_toNumber(value);
111 }
112 }
113 8 startLine = endLine+1;
114
1/1
✓ Call 0 invoked.
8 endLine = content.find('\n', startLine);
115 }
116
4/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
1 }
117 1 return *this;
118
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
1 }
119 4 std::string getInfos() {
120
4/4
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
4 std::stringstream project, build_id, file, infos;
121
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 std::string project_str, build_id_str, file_str;
122
6/6
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 16 taken 4 times.
6/6
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
4 build_id << "Build Id : " << m_majorNumber << "." << m_minorNumber << "." << m_buildNumber;
123
1/1
✓ Branch 1 taken 4 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
4 build_id_str = build_id.str();
124
1/1
✓ Call 0 invoked.
4 size_t row_len = build_id_str.size();
125
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
4 if (m_lastWriteStatus) {
126
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
4 file << "In file : " << m_buildFileHeader;
127 } else {
128
0/2
✗ Call 0 not invoked.
✗ Call 3 not invoked.
file << "failed to write to : " << m_buildFileHeader;
129 }
130
1/1
✓ Branch 1 taken 4 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
4 file_str = file.str();
131
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
4 if (row_len < file_str.size()) {
132
0/1
✗ Call 0 not invoked.
row_len = file_str.size();
133 }
134
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (!m_project.empty()) {
135
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
4 project << "Project : " << m_project;
136
1/1
✓ Branch 1 taken 4 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
4 project_str = project.str();
137
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
4 if (row_len < project_str.size()) {
138
0/1
✗ Call 0 not invoked.
row_len = project_str.size();
139 }
140 }
141
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 auto spliter = std::string(row_len + 6, '-'); // +6 for '-- ' and ' --'
142
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
4 infos << spliter << std::endl;
143
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (!m_project.empty()) {
144
6/6
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 8 taken 4 times.
✓ Branch 11 taken 4 times.
✓ Branch 14 taken 4 times.
✓ Branch 17 taken 4 times.
8/9
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 16 invoked.
✓ Call 19 invoked.
✗ Call 20 not invoked.
12 infos << "-- " << project_str << std::string(row_len - project_str.size(), ' ') << " --" << std::endl;
145 }
146
6/6
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 8 taken 4 times.
✓ Branch 11 taken 4 times.
✓ Branch 14 taken 4 times.
✓ Branch 17 taken 4 times.
8/9
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 16 invoked.
✓ Call 19 invoked.
✗ Call 20 not invoked.
8 infos << "-- " << build_id_str << std::string(row_len - build_id_str.size(), ' ') << " --" << std::endl;
147
6/6
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 8 taken 4 times.
✓ Branch 11 taken 4 times.
✓ Branch 14 taken 4 times.
✓ Branch 17 taken 4 times.
8/9
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 16 invoked.
✓ Call 19 invoked.
✗ Call 20 not invoked.
8 infos << "-- " << file_str << std::string(row_len - file_str.size(), ' ') << " --" << std::endl;
148
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
4 infos << spliter << std::endl;
149
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
8 return infos.str();
150
8/16
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
✗ Call 14 not invoked.
✗ Call 15 not invoked.
4 }
151 4 BuildInc& printInfos() {
152
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
4 std::cout << getInfos();
153 4 return *this;
154 }
155 1 const std::string& getProject() { return m_project; }
156 1 const std::string& getLabel() { return m_label; }
157 1 int32_t getMajor() { return m_majorNumber; }
158 1 int32_t getMinor() { return m_minorNumber; }
159 1 int32_t getBuildNumber() { return m_buildNumber; }
160 BuildInc& setProject(const std::string& vProject) {
161 m_project = vProject;
162 return *this;
163 }
164 BuildInc& setLabel(const std::string& vLabel) {
165 m_label = vLabel;
166 return *this;
167 }
168 BuildInc& setMajor(const int32_t vMajorNumber) {
169 m_majorNumber = vMajorNumber;
170 return *this;
171 }
172 BuildInc& setMinor(const int32_t vMinorNumber) {
173 m_minorNumber = vMinorNumber;
174 return *this;
175 }
176 BuildInc& setBuildNumber(const int32_t vBuildNumber) {
177 m_buildNumber = vBuildNumber;
178 return *this;
179 }
180 1 BuildInc& incBuildNumber() {
181 1 ++m_buildNumber;
182 1 return *this;
183 }
184 #ifdef EZ_FIG_FONT
185 2 FigFontGenerator& setFigFontFile(const std::string& vFigFontFile) {
186
1/1
✓ Call 0 invoked.
2 m_figFontGenerator.m_generator.load(vFigFontFile);
187 2 return m_figFontGenerator;
188 }
189 #endif // EZ_FIG_FONT
190 4 BuildInc& write() {
191 4 m_lastWriteStatus = false;
192
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::stringstream content;
193
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
4 content << "#pragma once" << std::endl;
194
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 content << std::endl;
195
6/6
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 16 taken 4 times.
6/6
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
4 content << "#define " << m_project << "_Label \"" << m_label << "\"" << std::endl;
196
5/5
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
5/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
4 content << "#define " << m_project << "_BuildNumber " << m_buildNumber << std::endl;
197
5/5
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
5/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
4 content << "#define " << m_project << "_MinorNumber " << m_minorNumber << std::endl;
198
5/5
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
5/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
4 content << "#define " << m_project << "_MajorNumber " << m_majorNumber << std::endl;
199
10/10
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 16 taken 4 times.
✓ Branch 19 taken 4 times.
✓ Branch 22 taken 4 times.
✓ Branch 25 taken 4 times.
✓ Branch 28 taken 4 times.
10/10
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✓ Call 21 invoked.
✓ Call 24 invoked.
✓ Call 27 invoked.
4 content << "#define " << m_project << "_BuildId \"" << m_majorNumber << "." << m_minorNumber << "." << m_buildNumber << "\"" << std::endl;
200 #ifdef EZ_FIG_FONT
201
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (m_figFontGenerator.isValid()) {
202
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::stringstream version;
203
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
4 if (m_figFontGenerator.m_useLabel) {
204
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
2 version << m_label << " ";
205 }
206
4/4
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
4 version << "v" << m_majorNumber << "." << m_minorNumber;
207
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
4 if (m_figFontGenerator.m_useBuildNumber) {
208
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
2 version << "." << m_buildNumber;
209 }
210
8/8
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 16 taken 4 times.
✓ Branch 19 taken 4 times.
✓ Branch 22 taken 4 times.
10/12
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✓ Call 21 invoked.
✓ Call 24 invoked.
✓ Call 25 invoked.
✗ Call 26 not invoked.
✗ Call 27 not invoked.
4 content << "#define " << m_project << "_FigFontLabel u8R\"(" << m_figFontGenerator.m_generator.printString(version.str()) << ")\"" << std::endl;
211
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
4 }
212 #endif // EZ_FIG_FONT
213
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::ofstream configFileWriter(m_buildFileHeader, std::ios::out);
214
2/3
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (!configFileWriter.bad()) {
215
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
4 configFileWriter << content.str();
216
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 configFileWriter.close();
217 4 m_lastWriteStatus = true;
218 }
219 4 return *this;
220
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
4 }
221
222 private:
223 // will parse a line '#define [PROJECT]_[KEY] [VALUE]'
224 // return true is succeed, false if the format is not recognized
225 8 bool m_parseDefine(const std::string& vRowContent, std::string& vOutProject, std::string& vOutKey, std::string& vOutValue) {
226
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
8 if (!vRowContent.empty()) {
227
1/1
✓ Call 0 invoked.
6 size_t def_pos = vRowContent.find("#define ");
228
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1 times.
6 if (def_pos != std::string::npos) {
229 5 def_pos += 8; // offset for '#define '
230
1/1
✓ Call 0 invoked.
5 size_t underScore_pos = vRowContent.find('_', def_pos);
231
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
5 if (underScore_pos != std::string::npos) {
232
1/1
✓ Branch 1 taken 5 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
5 vOutProject = vRowContent.substr(def_pos, underScore_pos - def_pos);
233 5 ++underScore_pos; // offset for '_'
234
1/1
✓ Call 0 invoked.
5 size_t space_pos = vRowContent.find(' ', underScore_pos);
235
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
5 if (space_pos != std::string::npos) {
236
1/1
✓ Branch 1 taken 5 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
5 vOutKey = vRowContent.substr(underScore_pos, space_pos - underScore_pos);
237 5 ++space_pos; // offset for ' '
238
2/2
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
5/6
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
5 vOutValue = m_trim(vRowContent.substr(space_pos));
239 5 return true;
240 }
241 }
242 }
243 }
244 3 return false;
245 }
246 3 int32_t m_toNumber(const std::string& vNum) {
247 3 int32_t ret = 0; // 0 is the default value
248 try {
249
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 ret = std::stoi(vNum);
250
0/1
✗ Call 0 not invoked.
} catch (...) {
251 }
252 3 return ret;
253 }
254 // will remove quotes
255 5 std::string m_trim(const std::string& vValue) {
256
1/1
✓ Call 0 invoked.
5 std::string ret;
257
2/2
✓ Branch 5 taken 25 times.
✓ Branch 6 taken 5 times.
2/2
✓ Decision 'true' taken 25 times.
✓ Decision 'false' taken 5 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
30 for (auto& c : vValue) {
258
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 4 times.
2/2
✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 4 times.
25 if (c != '\"') {
259
1/1
✓ Branch 1 taken 21 times.
1/1
✓ Call 0 invoked.
21 ret += c;
260 }
261 }
262 5 return ret;
263 }
264 };
265
266 } // namespace ez
267

Directory: include/ezlibs/
File: ezFigFont.hpp
Date: 2025-07-28 14:06:36
Warnings: 4 unchecked decisions!
Exec Total Coverage
Lines: 95 98 96.9%
Functions: 9 9 100.0%
Branches: 80 87 92.0%
Decisions: 32 44 72.7%
Calls: 104 125 83.2%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezFigFont is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <array>
30 #include <string>
31 #include <vector>
32 #include <cstdint>
33 #include <sstream>
34 #include <fstream>
35 #include <iostream>
36 #include <unordered_map>
37
38 #include "ezLog.hpp"
39
40 #ifndef EZ_FIG_FONT
41 #define EZ_FIG_FONT
42 #endif // EZ_FIG_FONT
43
44 namespace ez {
45
46 class FigFont {
47 private:
48 bool m_isValid{false};
49 struct Header {
50 uint8_t endChar{};
51 uint8_t hardblank{}; // Filling char
52 int32_t height{}; // char height
53 int32_t baseline{}; // base line from top
54 int32_t maxLength{}; // max width of achar
55 int32_t oldLayout{}; // Old Layout
56 int32_t commentLines{}; // Comments line count just after header line
57 int32_t printDirection{}; // printing direction
58 int32_t fullLayout{}; // Full Layout
59 int32_t codetagCount{}; // codeTagCount (optional)
60 std::vector<std::string> commentBlock;
61 } m_header;
62 struct Glyph {
63 std::string desc;
64 std::vector<std::string> rows;
65 };
66 std::unordered_map<size_t, Glyph> m_glyphs;
67
68 public:
69
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 FigFont() = default;
70 FigFont(const std::string& vFilePathName) : m_isValid(m_load(vFilePathName)) {}
71
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 ~FigFont() = default;
72 7 bool isValid() { return m_isValid; }
73 3 FigFont& load(const std::string& vFilePathName) {
74
1/1
✓ Call 0 invoked.
3 m_isValid = m_load(vFilePathName);
75 3 return *this;
76 }
77 5 std::string printString(const std::string& vPattern) {
78
1/1
✓ Call 0 invoked.
5 return m_printString(vPattern);
79 }
80
81 private:
82 3 bool m_load(const std::string& vFilePathName) {
83
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 std::ifstream file(vFilePathName);
84
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
3 if (!file.is_open()) {
85 #ifdef EZ_TOOLS_LOG
86
3/3
✓ Branch 1 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
5/6
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
2 LogVarError("Failed to open the file %s", vFilePathName.c_str());
87 #endif // EZ_TOOLS_LOG
88 1 return false;
89 }
90
91
1/1
✓ Call 0 invoked.
2 std::string header;
92
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 std::getline(file, header);
93
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 std::istringstream headerStream(header);
94
1/1
✓ Call 0 invoked.
2 std::string magicNumber;
95
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 headerStream >> magicNumber;
96
3/4
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 9 not invoked.
2 if (magicNumber.substr(0, 5) != "flf2a") {
97 #ifdef EZ_TOOLS_LOG
98
0/5
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
LogVarError("%s", "Not a valid FIGfont file");
99 #endif // EZ_TOOLS_LOG
100 return false;
101 }
102
103 /*
104 flf2a$ 6 5 20 15 3 0 143 229 NOTE: The first five characters in
105 | | | | | | | | | | the entire file must be "flf2a".
106 / / | | | | | | | \
107 Signature / / | | | | | \ Codetag_Count
108 Hardblank / / | | | \ Full_Layout*
109 Height / | | \ Print_Direction
110 Baseline / \ Comment_Lines
111 Max_Length Old_Layout*
112 */
113
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.hardblank = magicNumber[5];
114 headerStream >> //
115
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.height >> //
116
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.baseline >> //
117
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.oldLayout >> //
118
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.maxLength >> //
119
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.commentLines >> //
120
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.printDirection >> //
121
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.fullLayout >> //
122
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.codetagCount;
123
124
1/1
✓ Call 0 invoked.
2 std::string line;
125
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_header.commentBlock.reserve(m_header.commentLines);
126
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 2 times.
22 for (int i = 0; i < m_header.commentLines; ++i) {
127
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
20 std::getline(file, line);
128
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
20 m_header.commentBlock.push_back(line);
129 }
130 2 size_t idx = 0;
131 static constexpr size_t baseChar = 32;
132 static constexpr size_t required_chars_count = 127 - baseChar;
133 static constexpr size_t additionnal_chars_count = 7;
134 2 std::array<size_t, additionnal_chars_count> additionnal_chars{196, 214, 220, 228, 246, 252, 223};
135 2 size_t cChar = baseChar;
136
3/3
✓ Branch 1 taken 514 times.
✓ Branch 3 taken 512 times.
✓ Branch 4 taken 2 times.
0/1
? Decision couldn't be analyzed.
1/1
✓ Call 0 invoked.
514 while (file) {
137
1/1
✓ Call 0 invoked.
512 std::vector<std::string> asciiArt;
138
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 322 times.
2/2
✓ Decision 'true' taken 190 times.
✓ Decision 'false' taken 322 times.
512 if (idx < required_chars_count) {
139 190 cChar = idx + baseChar;
140
1/1
✓ Branch 1 taken 190 times.
0/1
? Decision couldn't be analyzed.
1/1
✓ Call 0 invoked.
190 if (!m_parseChar(file, cChar)) {
141 // return false;
142 }
143
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 308 times.
2/2
✓ Decision 'true' taken 14 times.
✓ Decision 'false' taken 308 times.
322 } else if (idx - required_chars_count < additionnal_chars_count) {
144
1/1
✓ Branch 1 taken 14 times.
1/1
✓ Call 0 invoked.
14 cChar = additionnal_chars.at(idx - required_chars_count);
145
1/1
✓ Branch 1 taken 14 times.
0/1
? Decision couldn't be analyzed.
1/1
✓ Call 0 invoked.
14 if (!m_parseChar(file, cChar)) {
146 // return false;
147 }
148 } else {
149
1/1
✓ Branch 1 taken 308 times.
0/1
? Decision couldn't be analyzed.
1/1
✓ Call 0 invoked.
308 if (!m_parseChar(file, 0)) {
150 // return false;
151 }
152 }
153 512 ++idx;
154
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
512 }
155 2 return true;
156
5/10
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
3 }
157
158 512 bool m_parseChar(std::ifstream& vFile, const size_t vChar) {
159
1/1
✓ Call 0 invoked.
512 std::string row;
160 512 size_t charCode = vChar;
161
1/1
✓ Call 0 invoked.
512 Glyph glyph;
162
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 204 times.
2/2
✓ Decision 'true' taken 308 times.
✓ Decision 'false' taken 204 times.
512 if (charCode < 32) {
163
1/1
✓ Branch 1 taken 308 times.
1/1
✓ Call 0 invoked.
308 std::getline(vFile, row);
164
1/1
✓ Call 0 invoked.
308 size_t spacePos = row.find(' ');
165
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 306 times.
✓ Decision 'false' taken 2 times.
308 if (spacePos != std::string::npos) {
166
1/1
✓ Branch 1 taken 306 times.
1/1
✓ Call 0 invoked.
306 const auto numStr = row.substr(0, spacePos);
167
1/1
✓ Branch 1 taken 306 times.
1/1
✓ Call 0 invoked.
306 const auto descStr = row.substr(spacePos + 1);
168
1/1
✓ Branch 1 taken 306 times.
1/1
✓ Call 0 invoked.
306 charCode = static_cast<size_t>(std::stoi(numStr));
169
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
306 } else {
170 2 return false;
171 }
172 }
173
1/1
✓ Branch 1 taken 510 times.
1/1
✓ Call 0 invoked.
510 glyph.rows.reserve(m_header.height);
174
2/2
✓ Branch 0 taken 4080 times.
✓ Branch 1 taken 510 times.
2/2
✓ Decision 'true' taken 4080 times.
✓ Decision 'false' taken 510 times.
4590 for (int i = 0; i < m_header.height; ++i) {
175
1/1
✓ Branch 1 taken 4080 times.
1/1
✓ Call 0 invoked.
4080 std::getline(vFile, row);
176
1/2
✓ Branch 1 taken 4080 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4080 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4080 if (!row.empty()) {
177
2/2
✓ Branch 1 taken 4590 times.
✓ Branch 2 taken 4080 times.
2/2
✓ Decision 'true' taken 4590 times.
✓ Decision 'false' taken 4080 times.
1/1
✓ Call 0 invoked.
8670 while (row.back() == '@') {
178
1/1
✓ Call 0 invoked.
4590 row.pop_back();
179 }
180
2/2
✓ Branch 1 taken 4072 times.
✓ Branch 2 taken 8 times.
2/2
✓ Decision 'true' taken 4072 times.
✓ Decision 'false' taken 8 times.
1/1
✓ Call 0 invoked.
4080 if (row.front() == ' ') {
181
1/1
✓ Branch 1 taken 4072 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
4072 row = row.substr(1);
182 }
183
2/2
✓ Branch 5 taken 28904 times.
✓ Branch 6 taken 4080 times.
2/2
✓ Decision 'true' taken 28904 times.
✓ Decision 'false' taken 4080 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
32984 for (auto& c : row) {
184
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 28740 times.
2/2
✓ Decision 'true' taken 164 times.
✓ Decision 'false' taken 28740 times.
28904 if (c == static_cast<char>(m_header.hardblank)) {
185 164 c = ' ';
186 }
187 }
188 }
189
1/1
✓ Branch 1 taken 4080 times.
1/1
✓ Call 0 invoked.
4080 glyph.rows.push_back(row);
190 }
191
2/2
✓ Branch 1 taken 510 times.
✓ Branch 4 taken 510 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
510 m_glyphs[charCode] = glyph;
192 510 return true;
193
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
512 }
194
195 5 std::string m_printString(const std::string& vPattern) {
196
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 std::stringstream ret;
197
1/1
✓ Call 0 invoked.
5 std::vector<std::string> rows;
198
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 rows.resize(m_header.height);
199 5 size_t row_idx = 0;
200
2/2
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 5 times.
2/2
✓ Decision 'true' taken 40 times.
✓ Decision 'false' taken 5 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
45 for (auto& row : rows) {
201
2/2
✓ Branch 4 taken 448 times.
✓ Branch 5 taken 40 times.
2/2
✓ Decision 'true' taken 448 times.
✓ Decision 'false' taken 40 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
488 for (const auto c : vPattern) {
202
2/2
✓ Branch 1 taken 448 times.
✓ Branch 4 taken 448 times.
4/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
448 row += m_getCharRow(c, row_idx);
203 }
204 40 ++row_idx;
205 // remove empty rows
206
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 6 times.
2/2
✓ Decision 'true' taken 34 times.
✓ Decision 'false' taken 6 times.
1/1
✓ Call 0 invoked.
40 if (row.find_first_not_of(" ") != std::string::npos) {
207
2/2
✓ Branch 1 taken 34 times.
✓ Branch 4 taken 34 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
34 ret << row << std::endl;
208 }
209 }
210
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
10 return ret.str();
211
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
5 }
212
213 448 std::string m_getCharRow(size_t vC, size_t vRowIdx) {
214
1/1
✓ Branch 1 taken 448 times.
1/1
✓ Call 0 invoked.
448 auto it = m_glyphs.find(vC);
215
1/2
✓ Branch 2 taken 448 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 448 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
448 if (it != m_glyphs.end()) {
216
1/2
✓ Branch 2 taken 448 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 448 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
448 if (vRowIdx < it->second.rows.size()) {
217
2/2
✓ Branch 2 taken 448 times.
✓ Branch 5 taken 448 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
448 return it->second.rows.at(vRowIdx);
218 }
219 }
220
0/1
✗ Call 0 not invoked.
return {};
221 }
222 };
223
224 }
225

Directory: include/ezlibs/
File: ezExpr.hpp
Date: 2025-07-28 14:06:36
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 408 431 94.7%
Functions: 87 89 97.8%
Branches: 419 472 88.8%
Decisions: 14 22 63.6%
Calls: 658 929 70.8%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezExpr is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #ifndef _USE_MATH_DEFINES
30 #define _USE_MATH_DEFINES
31 #endif // _USE_MATH_DEFINES
32
33 #include <array>
34 #include <math.h>
35 #include <string>
36 #include <vector>
37 #include <limits>
38 #include <memory>
39 #include <chrono>
40 #include <cstring>
41 #include <sstream>
42 #include <iostream>
43 #include <functional>
44 #include <unordered_map>
45
46 #ifndef DONT_DEFINE_DEFAULT_BUILTINS
47 #define DEFINE_DEFAULT_BUILTINS
48 #endif // DONT_DEFINE_DEFAULT_BUILTINS
49
50 #ifndef DONT_USE_PERFO_MEASURING
51 #define USE_PERFO_MEASURING
52 #endif // DONT_USE_PERFO_MEASURING
53
54 namespace ez {
55
56 // Class that encapsulates a string
57 class String {
58 private:
59 char* m_Data; // Pointer to the character string
60 size_t m_Length; // Length of the string
61
62 public:
63 // Default constructor: initializes members to nullptr and length to 0
64 997 String() : m_Data(nullptr), m_Length(0) {}
65
66 // Constructor from a std::string
67 24 String(const ::std::string& str) {
68
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 24 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
24 if (!str.empty()) {
69
1/1
✓ Call 0 invoked.
24 m_Length = str.size();
70
1/1
✓ Call 0 invoked.
24 m_Data = new char[m_Length + 1];
71
1/1
✓ Call 0 invoked.
24 ::std::memcpy(m_Data, str.data(), m_Length + 1);
72 } else {
73 m_Data = nullptr;
74 m_Length = 0;
75 }
76 24 }
77
78 // Constructor from a C-style string (const char*)
79 26010311 String(const char* str) {
80
1/2
✓ Branch 0 taken 26010311 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 26010311 times.
✗ Decision 'false' not taken.
26010311 if (str) {
81 26010311 m_Length = ::std::strlen(str);
82
1/1
✓ Call 0 invoked.
26010311 m_Data = new char[m_Length + 1];
83 26010311 ::std::memcpy(m_Data, str, m_Length + 1);
84 } else {
85 m_Data = nullptr;
86 m_Length = 0;
87 }
88 26010311 }
89
90 // Constructor from a single character
91 815 String(char ch) {
92 815 m_Length = 1;
93
1/1
✓ Call 0 invoked.
815 m_Data = new char[2];
94 815 m_Data[0] = ch;
95 815 m_Data[1] = '\0';
96 815 }
97
98 // Copy constructor
99 9848 String(const String& other) {
100
2/2
✓ Branch 0 taken 9768 times.
✓ Branch 1 taken 80 times.
2/2
✓ Decision 'true' taken 9768 times.
✓ Decision 'false' taken 80 times.
9848 if (other.m_Data) {
101 9768 m_Length = other.m_Length;
102
1/1
✓ Call 0 invoked.
9768 m_Data = new char[m_Length + 1];
103 9768 ::std::memcpy(m_Data, other.m_Data, m_Length + 1);
104 } else {
105 80 m_Data = nullptr;
106 80 m_Length = 0;
107 }
108 9848 }
109
110 // Move constructor
111 2252 String(String&& other) noexcept : m_Data(other.m_Data), m_Length(other.m_Length) {
112 2252 other.m_Data = nullptr;
113 2252 other.m_Length = 0;
114 2252 }
115
116 // Copy assignment operator
117 84000079 char operator[](const size_t idx) {
118 84000079 return m_Data[idx]; // no verification
119 }
120
121 // Copy assignment operator
122 558 String& operator=(const String& other) {
123
1/2
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 558 times.
✗ Decision 'false' not taken.
558 if (this != &other) { // Avoid self-assignment
124
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 521 times.
1/1
✓ Call 2 invoked.
558 delete[] m_Data; // Free existing memory
125
1/2
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 558 times.
✗ Decision 'false' not taken.
558 if (other.m_Data) {
126 558 m_Length = other.m_Length;
127
1/1
✓ Call 0 invoked.
558 m_Data = new char[m_Length + 1];
128 558 ::std::memcpy(m_Data, other.m_Data, m_Length + 1);
129 } else {
130 m_Data = nullptr;
131 m_Length = 0;
132 }
133 }
134 558 return *this;
135 }
136
137 // Move assignment operator
138 677 String& operator=(String&& other) noexcept {
139
1/2
✓ Branch 0 taken 677 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 677 times.
✗ Decision 'false' not taken.
677 if (this != &other) { // Avoid self-assignment
140
2/2
✓ Branch 0 taken 484 times.
✓ Branch 1 taken 193 times.
1/1
✓ Call 2 invoked.
677 delete[] m_Data; // Free existing memory
141 677 m_Data = other.m_Data;
142 677 m_Length = other.m_Length;
143 677 other.m_Data = nullptr; // Reset moved object
144 677 other.m_Length = 0;
145 }
146 677 return *this;
147 }
148
149 // Destructor: releases allocated memory
150
2/2
✓ Branch 0 taken 26020955 times.
✓ Branch 1 taken 3292 times.
1/1
✓ Call 2 invoked.
26024247 ~String() { delete[] m_Data; }
151
152 // Static method to create a String from a double
153 284 static String fromDouble(double value) {
154 char buffer[32];
155 284 ::std::snprintf(buffer, sizeof(buffer), "%.16g", value); // Convert double to string
156
1/1
✓ Branch 1 taken 284 times.
1/1
✓ Call 0 invoked.
568 return String(buffer);
157 }
158
159 // Method to create a std::string from a String
160 ::std::string to_string() const {
161 if (m_Data == nullptr) {
162 return {};
163 }
164 return std::string(m_Data, m_Length);
165 }
166
167 // Equality operator
168 88005411 bool operator==(const String& other) const {
169
2/2
✓ Branch 0 taken 3881 times.
✓ Branch 1 taken 88001530 times.
2/2
✓ Decision 'true' taken 3881 times.
✓ Decision 'false' taken 88001530 times.
88005411 if (m_Length != other.m_Length) {
170 3881 return false; // If lengths are different, strings are different
171 }
172 88001530 return ::std::memcmp(m_Data, other.m_Data, m_Length) == 0; // Compare data
173 }
174
175 // Inequality operator
176 bool operator!=(const String& other) const { return !(*this == other); }
177
178 // Equality operator with a C-style string
179 558 bool operator==(const char* str) const { return ::std::strcmp(m_Data, str) == 0; }
180
181 // Inequality operator with a C-style string
182 bool operator!=(const char* str) const { return ::std::strcmp(m_Data, str) != 0; }
183
184 // Returns the encapsulated C-style string
185
1/2
✓ Branch 0 taken 88028110 times.
✗ Branch 1 not taken.
88028110 const char* c_str() const { return m_Data ? m_Data : ""; }
186
187 // Returns the length of the string
188 232134615 size_t length() const { return m_Length; }
189
190 // Concatenation operator with another String
191 484 String operator+(const String& other) const {
192 484 size_t newLength = m_Length + other.m_Length; // Calculate new length
193
1/1
✓ Call 0 invoked.
484 char* newData = new char[newLength + 1]; // Allocate memory
194 484 ::std::memcpy(newData, m_Data, m_Length); // Copy first string
195 484 ::std::memcpy(newData + m_Length, other.m_Data, other.m_Length + 1); // Copy second string
196
1/1
✓ Call 0 invoked.
484 return String(newData); // Return new String
197 }
198
199 // Concatenation operator with a C-style string
200 145 String operator+(const char* str) const {
201 145 size_t strLength = ::std::strlen(str); // Calculate length of str
202 145 size_t newLength = m_Length + strLength; // Calculate new length
203
1/1
✓ Call 0 invoked.
145 char* newData = new char[newLength + 1]; // Allocate memory
204 145 ::std::memcpy(newData, m_Data, m_Length); // Copy first string
205 145 ::std::memcpy(newData + m_Length, str, strLength + 1); // Copy str
206
1/1
✓ Call 0 invoked.
145 return String(newData); // Return new String
207 }
208
209 // Stream output operator overload for displaying the string
210 friend ::std::ostream& operator<<(::std::ostream& os, const String& str) {
211 os << str.c_str(); // Write the string to the stream
212 return os;
213 }
214 };
215
216 } // namespace ez
217
218 namespace std {
219
220 // Specialization of std::hash to use ez::String as a key in containers
221 template <>
222 struct hash<ez::String> {
223 88027340 size_t operator()(const ez::String& s) const noexcept {
224 88027340 size_t hash = 0;
225
1/1
✓ Call 0 invoked.
88027340 const char* data = s.c_str();
226
2/2
✓ Branch 1 taken 144107217 times.
✓ Branch 2 taken 88027340 times.
2/2
✓ Decision 'true' taken 144107217 times.
✓ Decision 'false' taken 88027340 times.
1/1
✓ Call 0 invoked.
232134557 for (size_t i = 0; i < s.length(); ++i) {
227 144107217 hash = hash * 31 + static_cast<size_t>(data[i]); // Simple hash calculation
228 }
229 88027340 return hash;
230 }
231 };
232
233 } // namespace std
234
235 namespace ez {
236
237 // Overload of the + operator to allow concatenation of const char* and ez::String
238 29 static inline String operator+(const char* lhs, const String& rhs) {
239 29 size_t lhsLength = ::std::strlen(lhs); // Calculate length of lhs
240
1/1
✓ Call 0 invoked.
29 size_t newLength = lhsLength + rhs.length(); // Calculate new length
241
1/1
✓ Call 0 invoked.
29 char* newData = new char[newLength + 1]; // Allocate memory
242 29 ::std::memcpy(newData, lhs, lhsLength); // Copy lhs
243
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
29 ::std::memcpy(newData + lhsLength, rhs.c_str(), rhs.length() + 1); // Copy rhs
244
1/1
✓ Call 0 invoked.
29 return String(newData); // Return new String
245 }
246
247 // Definition of aliases for functions with different numbers of arguments
248 typedef ::std::function<double(double)> UnaryFunctor;
249 typedef ::std::function<double(double, double)> BinaryFunctor;
250 typedef ::std::function<double(double, double, double)> TernaryFunctor;
251 typedef ::std::unordered_map<String, double> VarContainer;
252 typedef ::std::unordered_map<String, double> ConstantContainer;
253
254 // Structure representing a function with its number of arguments and behavior
255 struct Function {
256 UnaryFunctor unaryFunctor = nullptr;
257 BinaryFunctor binaryFunctor = nullptr;
258 TernaryFunctor ternaryFunctor = nullptr;
259 size_t argCount = 0U;
260 };
261
262 // Container to store available functions
263 typedef ::std::unordered_map<String, Function> FunctionContainer;
264
265 // Definition of possible token types
266 enum class TokenType { NUMBER = 0, LPAREN, RPAREN, VARIABLE, OPERATOR, FUNCTION, SEPARATOR, Count };
267
268 // Structure representing a token (lexical unit)
269 struct Token {
270 TokenType type;
271 String value;
272 };
273
274 // Definition of possible error codes
275 enum class ErrorCode {
276 NONE = 0,
277 PARSE_ERROR,
278 EVALUATION_NAN,
279 EVALUATION_INF,
280 DIVISION_BY_ZERO,
281 UNKNOWN_NODE_TYPE,
282 EMPTY_PARENTHESIS,
283 VARIABLE_NOT_FOUND,
284 FUNCTION_NOT_FOUND,
285 OPERATOR_NOT_FOUND,
286 UNMATCHED_PARENTHESIS,
287 FUNCTION_WRONG_ARGUMENTS_COUNT,
288 Count
289 };
290
291 // Definition of possible node types in a syntax tree
292 enum class NodeType { NUMBER = 0, VARIABLE, OPERATOR, FUNCTION, Count };
293
294 // Structure representing a node in the syntax tree
295 struct Node {
296 NodeType type = NodeType::NUMBER;
297 String name;
298 double value = 0.0;
299 ::std::array<::std::shared_ptr<Node>, 3> childs{}; // Array of pointers to child nodes
300 ::std::array<double, 3> tmp{}; // for avoid allocation during evaluation
301 size_t childCount = 0;
302 };
303
304 // Class to manage exceptions specific to expression evaluation
305 class ExprException : public ::std::exception {
306 public:
307
1/1
✓ Branch 2 taken 56 times.
2/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
56 ExprException(ErrorCode code, const String& message) : m_Code(code), m_Message(message) {}
308
309 56 ErrorCode getCode() const { return m_Code; }
310
311 56 const char* what() const noexcept override {
312
1/1
✓ Call 0 invoked.
56 return m_Message.c_str(); // Return the error message
313 }
314
315 private:
316 ErrorCode m_Code;
317 String m_Message;
318 };
319
320 // Main class for evaluating mathematical expressions
321 class Expr {
322 private:
323 String m_Expr; // Expression to evaluate
324 Node m_RootExpr; // Root of the syntax tree
325 VarContainer m_ParsedVariables; // Container for variables found during parsing
326 VarContainer m_DefinedVariables; // Container for variables defined after parsing
327 ConstantContainer m_Constant; // Container for constants
328 FunctionContainer m_Functions; // Container for functions
329 double m_EvalResult = 0.0; // Evaluation result
330 bool m_Verbose = false; // Verbose mode
331 ::std::stringstream m_printExpr; // Stream to print the expression and result
332 ::std::chrono::duration<double, ::std::milli> m_Elapsed; // Evaluation time
333 ::std::chrono::steady_clock::time_point m_StartTime;
334 ::std::chrono::steady_clock::time_point m_EndTime;
335
336 public:
337
1/1
✓ Branch 7 taken 202 times.
9/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
202 Expr() {
338 #ifdef DEFINE_DEFAULT_BUILTINS
339
1/1
✓ Branch 1 taken 202 times.
1/1
✓ Call 0 invoked.
202 defineDefaultBuiltins();
340 #endif // DEFINE_DEFAULT_BUILTINS
341
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
202 }
342
343 202 void defineDefaultBuiltins() {
344 // Initialization of common constants
345
2/2
✓ Branch 1 taken 202 times.
✓ Branch 4 taken 202 times.
3/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
202 addConstant("pi", M_PI); // PI
346
2/2
✓ Branch 1 taken 202 times.
✓ Branch 4 taken 202 times.
3/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
202 addConstant("e", M_E); // e
347
348 // Initialization of common unary functions
349
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
231 addFunction("-", [](double a) { return -a; });
350
351
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
2000205 addFunction("abs", [](double a) { return ::std::abs(a); });
352
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("floor", [](double a) { return ::std::floor(a); });
353
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("ceil", [](double a) { return ::std::ceil(a); });
354
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("round", [](double a) { return ::std::round(a); });
355
356
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("fract", [](double a) { return a - ::std::floor(a); });
357
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("sign", [this](double a) { return m_Sign(a); });
358
359
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
4000205 addFunction("sin", [](double a) { return ::std::sin(a); });
360
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
2000205 addFunction("cos", [](double a) { return ::std::cos(a); });
361
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("tan", [](double a) { return ::std::tan(a); });
362
363
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("asin", [](double a) { return ::std::asin(a); });
364
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("acos", [](double a) { return ::std::acos(a); });
365
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("atan", [](double a) { return ::std::atan(a); });
366
367
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("sinh", [](double a) { return ::std::sinh(a); });
368
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("cosh", [](double a) { return ::std::cosh(a); });
369
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("tanh", [](double a) { return ::std::tanh(a); });
370
371
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("asinh", [](double a) { return ::std::asinh(a); });
372
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("acosh", [](double a) { return ::std::acosh(a); });
373
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("atanh", [](double a) { return ::std::atanh(a); });
374
375
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("ln", [](double a) { return ::std::log(a); });
376
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
206 addFunction("log", [](double a) { return ::std::log(a); });
377
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("log1p", [](double a) { return ::std::log1p(a); });
378
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
202 addFunction("logb", [](double a) { return ::std::logb(a); });
379
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("log2", [](double a) { return ::std::log2(a); });
380
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("log10", [](double a) { return ::std::log10(a); });
381
382
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
4000206 addFunction("sqrt", [](double a) { return ::std::sqrt(a); });
383
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
206 addFunction("exp", [](double a) { return ::std::exp(a); });
384
385
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
202 addFunction("fact", [this](double a) { return m_Factorial(a); });
386
387
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("saturate", [this](double a) { return m_Clamp(a, 0.0, 1.0); });
388
389 // Initialization of common binary functions
390
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
208 addFunction("mod", [](double a, double b) { return ::std::fmod(a, b); });
391
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
202 addFunction("pow", [](double a, double b) {
392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4000000 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4000000 times.
4000000 if (a < 0.0) {
393
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
throw ExprException(ErrorCode::EVALUATION_NAN, "Pow base value is negative");
394 }
395 4000000 return ::std::pow(a, b);
396 });
397
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("atan2", [](double a, double b) { return ::std::atan2(a, b); });
398
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("min", [this](double a, double b) { return m_Min(a, b); });
399
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("max", [this](double a, double b) { return m_Max(a, b); });
400
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("step", [this](double a, double b) { return m_Step(a, b); });
401
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
5/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
205 addFunction("hypot", [](double a, double b) { return ::std::hypot(a, b); });
402
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("smoothabs", [this](double a, double b) { return m_SmoothAbs(a, b); });
403
404 // Initialization of common ternary functions
405
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("clamp", [this](double a, double b, double c) { return m_Clamp(a, b, c); });
406
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("lerp", [this](double a, double b, double c) { return m_Mix(a, b, c); });
407
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✓ Call 12 invoked.
205 addFunction("mix", [this](double a, double b, double c) { return m_Mix(a, b, c); });
408
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
6/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✓ Call 11 invoked.
205 addFunction("smoothstep", [this](double a, double b, double c) { return m_SmoothStep(a, b, c); });
409 202 }
410
411 // Method to parse an expression
412 202 Expr& parse(const String& vExpr) {
413
1/1
✓ Branch 1 taken 202 times.
1/1
✓ Call 0 invoked.
202 m_Expr = vExpr; // Store the expression
414
1/1
✓ Call 0 invoked.
202 m_ParsedVariables.clear(); // clearing discoverd vairable during parsing
415
1/1
✓ Branch 1 taken 202 times.
1/1
✓ Call 0 invoked.
202 auto tokens = m_tokenize(m_Expr); // Tokenize the expression
416 202 size_t pos = 0;
417
1/1
✓ Branch 1 taken 171 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
202 m_RootExpr = m_parseExpression(tokens, pos, 0); // Parse the expression to create the syntax tree
418
419 // Check for remaining tokens after parsing
420
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 160 times.
2/2
✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 160 times.
1/1
✓ Call 0 invoked.
171 if (pos < tokens.size()) {
421 // If the next token is an unmatched closing parenthesis
422
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 8 times.
0/1
? Decision couldn't be analyzed.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
11 if (tokens[pos].value == ")") {
423
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
3 throw ExprException(ErrorCode::UNMATCHED_PARENTHESIS, "Unmatched parenthesis found at the end of the expression");
424 }
425 // If other tokens remain, which is also abnormal
426
2/2
✓ Branch 2 taken 8 times.
✓ Branch 5 taken 8 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
8 throw ExprException(ErrorCode::PARSE_ERROR, "Unexpected token found after complete parsing.");
427 }
428
429 160 return *this;
430
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
202 }
431
432 // Method to set the value of a variable
433 26000000 Expr& set(const String& vName, const double vValue, const bool vIfNotExist = false) {
434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26000000 times.
26000000 if (vIfNotExist) {
435
0/3
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
if (m_DefinedVariables.find(vName) != m_DefinedVariables.end()) { // If exists
436 return *this;
437 }
438 }
439
1/1
✓ Call 0 invoked.
26000000 m_DefinedVariables[vName] = vValue;
440 26000000 return *this;
441 }
442
443 // Method to evaluate the expression
444 24000136 Expr& eval() {
445
1/1
✓ Call 0 invoked.
24000136 m_evalNode(m_RootExpr, m_EvalResult); // Evaluate the root of the syntax tree
446 24000122 return *this;
447 }
448
449 Expr& startTime() {
450 m_StartTime = ::std::chrono::steady_clock::now(); // Start time
451 return *this;
452 }
453
454 Expr& endTime() {
455 m_EndTime = ::std::chrono::steady_clock::now(); // End time
456 return *this;
457 }
458
459 // Returns the evaluation time in milliseconds
460 double getEvalTime() {
461 m_Elapsed = m_EndTime - m_StartTime;
462 return m_Elapsed.count();
463 }
464
465 // Method to add a constant
466 404 Expr& addConstant(const String& vName, const double vValue) {
467
1/1
✓ Call 0 invoked.
404 m_Constant[vName] = vValue; // Add the constant
468 404 return *this;
469 }
470
471 // Method to add a unary function
472 5858 Expr& addFunction(const String& vName, const UnaryFunctor& functor) {
473
1/1
✓ Call 0 invoked.
5858 Function fun;
474
1/1
✓ Branch 1 taken 5858 times.
1/1
✓ Call 0 invoked.
5858 fun.unaryFunctor = functor;
475 5858 fun.argCount = 1;
476
2/2
✓ Branch 1 taken 5858 times.
✓ Branch 4 taken 5858 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
5858 m_Functions[vName] = fun;
477 5858 return *this;
478
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
5858 }
479
480 // Method to add a binary function
481 1616 Expr& addFunction(const String& vName, const BinaryFunctor& functor) {
482
1/1
✓ Call 0 invoked.
1616 Function fun;
483
1/1
✓ Branch 1 taken 1616 times.
1/1
✓ Call 0 invoked.
1616 fun.binaryFunctor = functor;
484 1616 fun.argCount = 2;
485
2/2
✓ Branch 1 taken 1616 times.
✓ Branch 4 taken 1616 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
1616 m_Functions[vName] = fun;
486 1616 return *this;
487
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
1616 }
488
489 // Method to add a ternary function
490 808 Expr& addFunction(const String& vName, const TernaryFunctor& functor) {
491
1/1
✓ Call 0 invoked.
808 Function fun;
492
1/1
✓ Branch 1 taken 808 times.
1/1
✓ Call 0 invoked.
808 fun.ternaryFunctor = functor;
493 808 fun.argCount = 3;
494
2/2
✓ Branch 1 taken 808 times.
✓ Branch 4 taken 808 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
808 m_Functions[vName] = fun;
495 808 return *this;
496
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
808 }
497
498 // Method to enable or disable verbose mode
499 40 Expr& setVerbose(bool vVerbose) {
500 40 m_Verbose = vVerbose;
501 40 return *this;
502 }
503
504 // Returns the evaluation result
505 24000000 double getResult() { return m_EvalResult; }
506
507 // Prints the expression and its result
508 Expr& print() {
509 m_printExpr = {};
510 m_printExpr << "Expr \"" << m_Expr << "\"";
511 for (const auto& it : m_DefinedVariables) {
512 m_printExpr << ", " << it.first << " = " << it.second;
513 }
514 m_printExpr << " => " << m_EvalResult;
515 ::std::cout << m_printExpr.str() << " (" << getEvalTime() << " ms)" << ::std::endl;
516 return *this;
517 }
518
519 // Checks if the evaluation result is close to a given value
520
1/1
✓ Call 0 invoked.
122 bool check(const double vValue) { return (::std::abs(m_EvalResult - vValue) < 0.001); }
521
522 // test if a variable found during parsing exist
523 bool isParsedVariableExist(const String& vName) { return (m_ParsedVariables.find(vName) != m_ParsedVariables.end()); }
524
525 // Returns variables as a constant reference
526 const VarContainer& getParsedVars() { return m_ParsedVariables; }
527
528 // Returns variables as a modifiable reference
529 VarContainer& getParsedVarsRef() { return m_ParsedVariables; }
530
531 // test if a defined variable exist
532 bool isDefinedVariableExist(const String& vName) { return (m_DefinedVariables.find(vName) != m_ParsedVariables.end()); }
533
534 // Returns defined variables as a constant reference
535 const VarContainer& getDefinedVars() { return m_DefinedVariables; }
536
537 // Returns defined variables as a modifiable reference
538 VarContainer& getDefinedVarsRef() { return m_DefinedVariables; }
539
540 protected:
541 // Tokenize the expression
542 202 ::std::vector<Token> m_tokenize(const String& expr) {
543
1/1
✓ Call 0 invoked.
202 ::std::vector<Token> tokens;
544
2/2
✓ Branch 2 taken 202 times.
✓ Branch 5 taken 202 times.
4/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
202 ::std::istringstream stream(expr.c_str());
545 202 char ch = 0;
546
4/4
✓ Branch 1 taken 1206 times.
✓ Branch 4 taken 1206 times.
✓ Branch 6 taken 1004 times.
✓ Branch 7 taken 202 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
1206 while (stream >> ch) {
547
3/4
✓ Branch 0 taken 722 times.
✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 722 times.
1004 if (::std::isdigit(ch) || ch == '.') {
548
1/1
✓ Branch 1 taken 282 times.
1/1
✓ Call 0 invoked.
282 stream.putback(ch);
549 double number;
550
1/1
✓ Branch 1 taken 282 times.
1/1
✓ Call 0 invoked.
282 stream >> number;
551
1/1
✓ Branch 1 taken 282 times.
2/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
282 tokens.push_back({TokenType::NUMBER, String::fromDouble(number)});
552
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 521 times.
1004 } else if (::std::isalpha(ch)) {
553
1/1
✓ Branch 1 taken 201 times.
1/1
✓ Call 0 invoked.
201 String identifier(ch);
554
8/8
✓ Branch 1 taken 681 times.
✓ Branch 4 taken 681 times.
✓ Branch 6 taken 675 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 480 times.
✓ Branch 9 taken 195 times.
✓ Branch 10 taken 480 times.
✓ Branch 11 taken 201 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
681 while (stream.get(ch) && ::std::isalnum(ch)) {
555
2/2
✓ Branch 1 taken 480 times.
✓ Branch 4 taken 480 times.
5/6
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
480 identifier = identifier + String(ch);
556 }
557
1/1
✓ Branch 1 taken 201 times.
1/1
✓ Call 0 invoked.
201 stream.putback(ch);
558
1/1
✓ Branch 1 taken 201 times.
2/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
201 tokens.push_back({TokenType::VARIABLE, identifier}); // Traitement g�n�rique comme identifiant
559
2/2
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 356 times.
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
722 } else if (ch == '(') {
560
1/1
✓ Branch 1 taken 165 times.
2/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
165 tokens.push_back({TokenType::LPAREN, String("(")});
561
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 191 times.
356 } else if (ch == ')') {
562
1/1
✓ Branch 1 taken 165 times.
2/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
165 tokens.push_back({TokenType::RPAREN, String(")")});
563
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 130 times.
191 } else if (ch == ',') {
564
1/1
✓ Branch 1 taken 61 times.
2/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
61 tokens.push_back({TokenType::SEPARATOR, String(",")});
565 } else {
566
1/1
✓ Branch 1 taken 130 times.
1/1
✓ Call 0 invoked.
130 String op(ch);
567
14/16
✓ Branch 1 taken 134 times.
✓ Branch 4 taken 134 times.
✓ Branch 6 taken 124 times.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 88 times.
✓ Branch 9 taken 36 times.
✓ Branch 10 taken 11 times.
✓ Branch 11 taken 77 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 7 times.
✓ Branch 14 taken 4 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 130 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
134 while (stream.get(ch) && !::std::isalnum(ch) && ch != ' ' && ch != '(' && ch != ')' && ch != ',') {
568
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
5/6
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
4 op = op + String(ch);
569 }
570
1/1
✓ Branch 1 taken 130 times.
1/1
✓ Call 0 invoked.
130 stream.putback(ch);
571
1/1
✓ Branch 1 taken 130 times.
2/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
130 tokens.push_back({TokenType::OPERATOR, op});
572
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
130 }
573 }
574
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 162 times.
202 if (m_Verbose) {
575
2/2
✓ Branch 1 taken 40 times.
✓ Branch 4 taken 40 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
40 m_log("Tokens: ");
576
2/2
✓ Branch 4 taken 143 times.
✓ Branch 5 taken 40 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
183 for (const auto& token : tokens) {
577
2/2
✓ Branch 1 taken 143 times.
✓ Branch 4 taken 143 times.
4/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
143 m_log(token.value + " ");
578 }
579
2/2
✓ Branch 1 taken 40 times.
✓ Branch 4 taken 40 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
40 m_log("\n");
580 }
581 404 return tokens;
582
7/9
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✗ Call 19 not invoked.
✗ Call 20 not invoked.
1206 }
583
584 // Logs messages if verbose mode is enabled
585 225 void m_log(const String& message) {
586
1/2
✓ Branch 0 taken 225 times.
✗ Branch 1 not taken.
225 if (m_Verbose) {
587
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
225 ::std::cout << message.c_str();
588 }
589 225 }
590
591 // Evaluate a node in the syntax tree
592 128000369 void m_evalNode(Node& node, double& vOutResult) {
593
4/5
✓ Branch 0 taken 32000197 times.
✓ Branch 1 taken 42000020 times.
✓ Branch 2 taken 38000003 times.
✓ Branch 3 taken 16000149 times.
✗ Branch 4 not taken.
128000369 switch (node.type) {
594 32000197 case NodeType::NUMBER: {
595 32000197 vOutResult = node.value;
596 32000197 } break;
597 42000020 case NodeType::OPERATOR: {
598
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
42000020 m_evalNode(*node.childs[0], node.tmp[0]); // left
599
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
42000016 m_evalNode(*node.childs[1], node.tmp[1]); // right
600
2/2
✓ Branch 1 taken 24000000 times.
✓ Branch 2 taken 18000016 times.
1/1
✓ Call 0 invoked.
42000016 if (node.name[0] == '+') {
601
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
24000000 vOutResult = node.tmp[0] + node.tmp[1];
602
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18000016 times.
1/1
✓ Call 0 invoked.
18000016 } else if (node.name[0] == '-') {
603
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
vOutResult = node.tmp[0] - node.tmp[1];
604
2/2
✓ Branch 1 taken 12000000 times.
✓ Branch 2 taken 6000016 times.
1/1
✓ Call 0 invoked.
18000016 } else if (node.name[0] == '*') {
605
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
12000000 vOutResult = node.tmp[0] * node.tmp[1];
606
2/2
✓ Branch 1 taken 6000008 times.
✓ Branch 2 taken 8 times.
1/1
✓ Call 0 invoked.
6000016 } else if (node.name[0] == '/') {
607
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 6000003 times.
1/1
✓ Call 0 invoked.
6000008 if (node.tmp[1] == 0.0) {
608
2/2
✓ Branch 2 taken 5 times.
✓ Branch 5 taken 5 times.
4/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
5 throw ExprException(ErrorCode::DIVISION_BY_ZERO, "Division by zero");
609 }
610
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
6000003 vOutResult = node.tmp[0] / node.tmp[1];
611
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
1/1
✓ Call 0 invoked.
8 } else if (node.name[0] == '^') {
612
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
1/1
✓ Call 0 invoked.
4 if (node.tmp[0] < 0.0) {
613
2/2
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
4/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
1 throw ExprException(ErrorCode::EVALUATION_NAN, "Pow base value is negative");
614 }
615
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 vOutResult = ::std::pow(node.tmp[0], node.tmp[1]);
616
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
4 } else if (node.name[0] == '%') {
617
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
1/1
✓ Call 0 invoked.
4 if (node.tmp[1] == 0.0) {
618
2/2
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
4/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
1 throw ExprException(ErrorCode::DIVISION_BY_ZERO, "Division by zero");
619 }
620
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 vOutResult = ::std::fmod(node.tmp[0], node.tmp[1]);
621 }
622 42000009 } break;
623 38000003 case NodeType::VARIABLE: {
624
1/1
✓ Branch 1 taken 38000003 times.
1/1
✓ Call 0 invoked.
38000003 auto it = m_DefinedVariables.find(node.name);
625
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 38000000 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
38000003 if (it == m_DefinedVariables.end()) {
626
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
3 throw ExprException(ErrorCode::VARIABLE_NOT_FOUND, "Variable not found: " + node.name);
627 }
628
1/1
✓ Call 0 invoked.
38000000 vOutResult = it->second;
629 38000000 } break;
630 16000149 case NodeType::FUNCTION: {
631
1/1
✓ Branch 1 taken 16000149 times.
1/1
✓ Call 0 invoked.
16000149 auto it = m_Functions.find(node.name);
632
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 16000146 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
16000149 if (it == m_Functions.end()) {
633 // Special case handling for the "!" operator (factorial)
634
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
3 if (node.name[0] == '!') {
635
1/1
✓ Branch 4 taken 3 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
3 m_evalNode(*node.childs[0], node.tmp[0]);
636
1/1
✓ Branch 2 taken 3 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 vOutResult = m_Factorial(node.tmp[0]); // Call the factorial function
637 } else {
638
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
throw ExprException(ErrorCode::FUNCTION_NOT_FOUND, "Function not found: " + node.name);
639 }
640 } else {
641
2/2
✓ Branch 1 taken 12000110 times.
✓ Branch 2 taken 4000036 times.
1/1
✓ Call 0 invoked.
16000146 if (it->second.argCount == 1) {
642
1/1
✓ Branch 4 taken 12000110 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
12000110 m_evalNode(*node.childs[0], node.tmp[0]);
643
1/1
✓ Branch 3 taken 12000110 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
12000110 vOutResult = it->second.unaryFunctor(node.tmp[0]); // first
644
2/2
✓ Branch 1 taken 4000024 times.
✓ Branch 2 taken 12 times.
1/1
✓ Call 0 invoked.
4000036 } else if (it->second.argCount == 2) {
645
1/1
✓ Branch 4 taken 4000024 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
4000024 m_evalNode(*node.childs[0], node.tmp[0]); // first
646
1/1
✓ Branch 4 taken 4000024 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
4000024 m_evalNode(*node.childs[1], node.tmp[1]); // second
647
1/1
✓ Branch 4 taken 4000024 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
4000024 vOutResult = it->second.binaryFunctor(node.tmp[0], node.tmp[1]);
648
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
12 } else if (it->second.argCount == 3) {
649
1/1
✓ Branch 4 taken 12 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
12 m_evalNode(*node.childs[0], node.tmp[0]); // first
650
1/1
✓ Branch 4 taken 12 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
12 m_evalNode(*node.childs[1], node.tmp[1]); // second
651
1/1
✓ Branch 4 taken 12 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
12 m_evalNode(*node.childs[2], node.tmp[2]); // third
652
1/1
✓ Branch 5 taken 12 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
12 vOutResult = it->second.ternaryFunctor(node.tmp[0], node.tmp[1], node.tmp[2]);
653 }
654 }
655 16000149 } break;
656
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
default: throw ExprException(ErrorCode::UNKNOWN_NODE_TYPE, "Unknown node type");
657 }
658
659 // V�rification du r�sultat pour NaN ou Inf
660
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 128000353 times.
1/1
✓ Call 0 invoked.
128000355 if (::std::isnan(vOutResult)) {
661
2/2
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
4/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
2 throw ExprException(ErrorCode::EVALUATION_NAN, "Result is NaN");
662
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 128000351 times.
1/1
✓ Call 0 invoked.
128000353 } else if (::std::isinf(vOutResult)) {
663
2/2
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
4/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
2 throw ExprException(ErrorCode::EVALUATION_INF, "Result is Inf");
664 }
665
666
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 128000349 times.
128000351 if (m_Verbose) {
667
4/4
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 10 taken 2 times.
7/10
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 13 invoked.
✓ Call 14 invoked.
✗ Call 15 not invoked.
✗ Call 16 not invoked.
✗ Call 17 not invoked.
2 m_log("Evaluating Node: " + String::fromDouble(vOutResult) + "\n");
668 }
669 128000351 }
670
671 // Parse an expression to create a syntax tree
672 490 Node m_parseExpression(::std::vector<Token>& tokens, size_t& pos, int precedence) {
673
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 489 times.
1/1
✓ Call 0 invoked.
490 if (pos >= tokens.size()) {
674
2/2
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
4/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
1 throw ExprException(ErrorCode::PARSE_ERROR, "Unexpected end of expression");
675 }
676
1/1
✓ Call 0 invoked.
489 Node node = m_parseFactor(tokens, pos);
677
2/2
✓ Branch 1 taken 337 times.
✓ Branch 2 taken 193 times.
1/1
✓ Call 0 invoked.
530 while (pos < tokens.size()) {
678
1/1
✓ Branch 2 taken 337 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
337 String op = tokens[pos].value;
679 337 int opPrecedence = 0;
680
2/2
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 244 times.
1/1
✓ Call 0 invoked.
337 if (tokens[pos].type == TokenType::OPERATOR) {
681
14/16
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 50 times.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26 times.
✓ Branch 8 taken 17 times.
✓ Branch 10 taken 12 times.
✓ Branch 11 taken 14 times.
✓ Branch 13 taken 8 times.
✓ Branch 14 taken 4 times.
✓ Branch 16 taken 4 times.
✓ Branch 17 taken 4 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 4 times.
✓ Branch 21 taken 89 times.
✓ Branch 22 taken 4 times.
7/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
93 if (op == "+" || op == "-" || op == "*" || op == "/" || op == "^" || op == "%" || op == "!") {
682
9/10
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 50 times.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 22 times.
✓ Branch 8 taken 17 times.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 14 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 4 times.
5/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
89 opPrecedence = (op == "+" || op == "-") ? 1 : (op == "*" || op == "/" || op == "%") ? 2 : 3;
683 } else {
684
2/2
✓ Branch 2 taken 4 times.
✓ Branch 5 taken 4 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
4 throw ExprException(ErrorCode::OPERATOR_NOT_FOUND, "Operator not found: " + op);
685 }
686 }
687
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 77 times.
333 if (opPrecedence <= precedence) {
688 256 break;
689 }
690 77 ++pos;
691
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 74 times.
1/1
✓ Call 0 invoked.
77 if (pos >= tokens.size()) {
692
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
3 throw ExprException(ErrorCode::PARSE_ERROR, "Incomplete expression after operator: " + op);
693 }
694
1/1
✓ Branch 1 taken 69 times.
1/1
✓ Call 0 invoked.
74 Node rightNode = m_parseExpression(tokens, pos, opPrecedence);
695
1/1
✓ Call 0 invoked.
69 Node opNode;
696 69 opNode.type = NodeType::OPERATOR;
697
1/1
✓ Branch 1 taken 69 times.
1/1
✓ Call 0 invoked.
69 opNode.name = op;
698 69 opNode.childCount = 2;
699
1/1
✓ Branch 1 taken 69 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
69 opNode.childs[0] = ::std::make_shared<Node>(node);
700
1/1
✓ Branch 1 taken 69 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
69 opNode.childs[1] = ::std::make_shared<Node>(rightNode);
701
1/1
✓ Branch 1 taken 69 times.
1/1
✓ Call 0 invoked.
69 node = opNode;
702
4/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
✓ Call 7 invoked.
337 }
703 449 return node;
704
1/1
✓ Call 0 invoked.
12 }
705
706 // Parse a factor in an expression (number, variable, parenthesis, function)
707 519 Node m_parseFactor(::std::vector<Token>& tokens, size_t& pos) {
708
1/1
✓ Call 0 invoked.
519 Node node;
709
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 519 times.
1/1
✓ Call 0 invoked.
519 if (pos >= tokens.size()) {
710
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
throw ExprException(ErrorCode::PARSE_ERROR, "Unexpected end of expression");
711 }
712
713
2/2
✓ Branch 1 taken 258 times.
✓ Branch 2 taken 261 times.
1/1
✓ Call 0 invoked.
519 if (tokens[pos].type == TokenType::NUMBER) {
714 258 node.type = NodeType::NUMBER;
715
2/2
✓ Branch 3 taken 258 times.
✓ Branch 6 taken 258 times.
5/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
258 node.value = ::std::stod(tokens[pos].value.c_str());
716 258 ++pos;
717
718 // Gestion de l'op�rateur postfix� "!" pour les nombres
719
8/8
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 22 times.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 193 times.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 38 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 253 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
258 if (pos < tokens.size() && tokens[pos].type == TokenType::OPERATOR && tokens[pos].value == "!") {
720
1/1
✓ Call 0 invoked.
5 Node opNode;
721 5 opNode.type = NodeType::FUNCTION;
722
1/1
✓ Branch 1 taken 5 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
5 opNode.name = "!";
723
1/1
✓ Branch 1 taken 5 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
5 opNode.childs[0] = ::std::make_shared<Node>(node);
724 5 opNode.childCount = 1;
725
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 node = opNode; // Remplacer le n�ud par l'op�rateur postfix�
726 5 ++pos;
727
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
5 }
728
2/2
✓ Branch 1 taken 199 times.
✓ Branch 2 taken 62 times.
1/1
✓ Call 0 invoked.
261 } else if (tokens[pos].type == TokenType::VARIABLE) {
729
1/1
✓ Branch 2 taken 199 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
199 String identifier = tokens[pos].value;
730 199 ++pos;
731
732
6/6
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 143 times.
✓ Branch 5 taken 50 times.
✓ Branch 6 taken 143 times.
✓ Branch 7 taken 56 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
199 if (pos < tokens.size() && tokens[pos].type == TokenType::LPAREN) {
733
1/1
✓ Branch 1 taken 143 times.
1/1
✓ Call 0 invoked.
143 auto it = m_Functions.find(identifier);
734
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 140 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
143 if (it == m_Functions.end()) {
735
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
3 throw ExprException(ErrorCode::FUNCTION_NOT_FOUND, "Function not found: " + identifier);
736 }
737
738 140 ++pos; // Passer la parenth�se ouvrante
739
740
5/6
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 139 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 139 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
140 if (pos < tokens.size() && tokens[pos].type == TokenType::RPAREN) {
741
2/2
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
1 throw ExprException(ErrorCode::FUNCTION_WRONG_ARGUMENTS_COUNT, "Function called with incorrect number of arguments: " + identifier);
742 }
743
744 139 node.type = NodeType::FUNCTION;
745
1/1
✓ Branch 1 taken 139 times.
1/1
✓ Call 0 invoked.
139 node.name = identifier;
746
2/2
✓ Branch 1 taken 137 times.
✓ Branch 4 taken 137 times.
6/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 10 not invoked.
139 node.childs[0] = ::std::make_shared<Node>(m_parseExpression(tokens, pos, 0));
747 137 node.childCount = 1;
748
749
5/6
✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 56 times.
✓ Branch 5 taken 136 times.
✓ Branch 6 taken 56 times.
✓ Branch 7 taken 136 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
192 while (pos < tokens.size() && tokens[pos].type == TokenType::SEPARATOR) {
750 56 ++pos;
751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (node.childCount >= 3) {
752
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
throw ExprException(ErrorCode::PARSE_ERROR, "Too many arguments provided for function: " + identifier);
753 }
754
2/2
✓ Branch 1 taken 55 times.
✓ Branch 4 taken 55 times.
6/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 10 not invoked.
56 node.childs[node.childCount++] = ::std::make_shared<Node>(m_parseExpression(tokens, pos, 0));
755 }
756
757
3/6
✓ Branch 1 taken 136 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 136 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 136 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
136 if (pos >= tokens.size() || tokens[pos].type != TokenType::RPAREN) {
758
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
throw ExprException(ErrorCode::UNMATCHED_PARENTHESIS, "Unmatched parenthesis");
759 }
760 136 ++pos;
761
762
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 133 times.
1/1
✓ Call 0 invoked.
136 if (node.childCount != it->second.argCount) {
763
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
3 throw ExprException(ErrorCode::FUNCTION_WRONG_ARGUMENTS_COUNT, "Incorrect number of arguments for function: " + identifier);
764 }
765
766 } else {
767 // Gestion des variables (non-fonctions et non-constantes)
768
1/1
✓ Branch 1 taken 56 times.
1/1
✓ Call 0 invoked.
56 auto it = m_Constant.find(identifier);
769
2/2
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 44 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
56 if (it != m_Constant.end()) {
770 12 node.type = NodeType::NUMBER;
771
1/1
✓ Call 0 invoked.
12 node.value = it->second;
772 } else {
773 44 node.type = NodeType::VARIABLE;
774
1/1
✓ Branch 1 taken 44 times.
1/1
✓ Call 0 invoked.
44 node.name = identifier;
775
1/1
✓ Branch 1 taken 44 times.
1/1
✓ Call 0 invoked.
44 m_ParsedVariables[identifier] = 0.0; // Ajout de la variable trouv�e avec une valeur par d�faut de 0.0
776 }
777
778 // Gestion de l'op�rateur postfix� "!" pour les variables
779
6/8
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 18 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 32 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 56 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
56 if (pos < tokens.size() && tokens[pos].type == TokenType::OPERATOR && tokens[pos].value == "!") {
780
0/1
✗ Call 0 not invoked.
Node opNode;
781 opNode.type = NodeType::FUNCTION;
782
0/3
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
opNode.name = "!";
783
0/4
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
opNode.childs[0] = ::std::make_shared<Node>(node);
784 opNode.childCount = 1;
785
0/1
✗ Call 0 not invoked.
node = opNode; // Remplacer le n�ud par l'op�rateur postfix�
786 ++pos;
787 }
788 }
789
2/2
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 42 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
261 } else if (tokens[pos].type == TokenType::LPAREN) {
790 20 ++pos;
791
5/6
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 19 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
20 if (pos < tokens.size() && tokens[pos].type == TokenType::RPAREN) {
792
2/2
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
1 throw ExprException(ErrorCode::EMPTY_PARENTHESIS, "Empty parenthesis found");
793 }
794
1/1
✓ Branch 1 taken 17 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
19 node = m_parseExpression(tokens, pos, 0);
795
5/6
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 14 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
17 if (pos >= tokens.size() || tokens[pos].type != TokenType::RPAREN) {
796
2/2
✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
3 throw ExprException(ErrorCode::UNMATCHED_PARENTHESIS, "Unmatched parenthesis");
797 }
798 14 ++pos;
799
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 4 times.
1/1
✓ Call 0 invoked.
42 } else if (tokens[pos].type == TokenType::OPERATOR) {
800
1/1
✓ Branch 2 taken 38 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
38 String op = tokens[pos].value;
801
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 8 times.
1/1
✓ Call 0 invoked.
38 if (op == "-") {
802 30 node.type = NodeType::FUNCTION;
803
1/1
✓ Branch 2 taken 30 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
30 node.name = tokens[pos].value;
804 30 ++pos;
805
2/2
✓ Branch 1 taken 29 times.
✓ Branch 4 taken 29 times.
6/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 10 not invoked.
30 node.childs[0] = ::std::make_shared<Node>(m_parseFactor(tokens, pos));
806 29 node.childCount = 1;
807
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
1/1
✓ Call 0 invoked.
8 } else if (op == "!") {
808
2/2
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
5/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
2 throw ExprException(ErrorCode::PARSE_ERROR, "Factorial operator '!' cannot be used alone or in prefix position.");
809 } else {
810
2/2
✓ Branch 3 taken 6 times.
✓ Branch 6 taken 6 times.
6/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
6 throw ExprException(ErrorCode::PARSE_ERROR, "Unexpected operator: " + tokens[pos].value);
811 }
812
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
38 } else {
813
2/2
✓ Branch 3 taken 4 times.
✓ Branch 6 taken 4 times.
6/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
4 throw ExprException(ErrorCode::PARSE_ERROR, "Unexpected token: " + tokens[pos].value);
814 }
815
816 490 return node;
817
1/1
✓ Call 0 invoked.
29 }
818
819 /////////////////////////////////////////
820 //// BUILTINS FUNCTIONS /////////////////
821 /////////////////////////////////////////
822
823 // Calculate a factorial
824 3 double m_Factorial(double vValue) {
825
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (vValue < 0 || ::std::floor(vValue) != vValue) {
826
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
throw ExprException(ErrorCode::PARSE_ERROR, "Factorial is not defined for negative or non-integer values.");
827 }
828 3 double result = 1;
829 3 const auto count = static_cast<int>(vValue);
830
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (int i = 1; i <= count; ++i) {
831 8 result *= i;
832 }
833 3 return result;
834 }
835
836 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/min.xhtml
837 12 double m_Min(double vX, double vY) {
838
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 if (vX < vY) {
839 8 return vX;
840 }
841 4 return vY;
842 }
843
844 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/max.xhtml
845 12 double m_Max(double vX, double vY) {
846
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 if (vX > vY) {
847 9 return vX;
848 }
849 3 return vY;
850 }
851
852 // https://www.shadertoy.com/???? : sqrt(v*v+k) with k >= 0
853
1/1
✓ Call 0 invoked.
3 double m_SmoothAbs(double vV, double vK) { return ::std::sqrt(vV * vV + ::std::abs(vK)); }
854
855 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/clamp.xhtml
856 // Clamp (glsl), Saturate (hlsl)
857
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
9 double m_Clamp(double vX, double vMinVal, double vMaxVal) { return m_Min(m_Max(vX, vMinVal), vMaxVal); }
858
859 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/smoothstep.xhtml
860 3 double m_SmoothStep(double vEdge0, double vEdge1, double vX) {
861
1/1
✓ Call 0 invoked.
3 double t = m_Clamp((vX - vEdge0) / (vEdge1 - vEdge0), 0.0, 1.0);
862 3 return t * t * (3.0 - 2.0 * t);
863 }
864
865 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/mix.xhtml
866 // Mix (glsl), lerp (hlsl)
867 6 double m_Mix(double vX, double vY, double vA) { return vX * (1.0 - vA) + vY * vA; }
868
869 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/step.xhtml
870
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 double m_Step(double vEdge, double vX) { return vX < vEdge ? 0.0 : 1.0; }
871
872 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/sign.xhtml
873 3 double m_Sign(double vX) {
874
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (vX < 0.0) {
875 1 return -1.0;
876
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (vX > 0.0) {
877 1 return 1.0;
878 }
879 1 return 0.0;
880 }
881 };
882
883 } // namespace ez
884

Directory: include/ezlibs/
File: ezXml.hpp
Date: 2025-07-28 14:06:36
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 203 236 86.0%
Functions: 32 40 80.0%
Branches: 164 195 84.1%
Decisions: 72 84 85.7%
Calls: 216 285 75.8%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezXml is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 // ezXml is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
29
30 #include <map>
31 #include <stack>
32 #include <string>
33 #include <vector>
34 #include <cstdint>
35 #include <cassert>
36 #include <sstream>
37 #include <ostream>
38 #include <fstream>
39
40 namespace ez {
41 class Xml;
42
43 namespace xml {
44
45 class Node;
46
47 typedef std::vector<Node> Nodes;
48
49 class Node {
50 friend class ez::Xml;
51
52 public:
53 enum class Type {
54 None = 0,
55 Token,
56 Comment
57 };
58
59 class Attribute {
60 private:
61 std::string m_value;
62 public:
63
1/1
✓ Call 0 invoked.
12 Attribute() = default;
64
65
1/1
✓ Call 0 invoked.
12 explicit Attribute(const std::string &vValue) : m_value(vValue) {}
66
67 template<typename T>
68 Attribute &operator<<(const T &vValue) {
69
0/1
✗ Call 0 not invoked.
std::ostringstream vOut;
70
0/1
✗ Call 0 not invoked.
vOut << vValue;
71
0/3
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
m_value = vOut.str();
72 return *this;
73 }
74
75 12 friend std::ostream& operator<<(std::ostream& os, const Attribute& attr) {
76
1/1
✓ Call 0 invoked.
12 os << attr.m_value;
77 12 return os;
78 }
79
80 12 const std::string& getValue() const {
81 12 return m_value;
82 }
83 };
84
85 private:
86 std::string m_name;
87 std::map<std::string, Attribute> m_attributes;
88 std::string m_content;
89 std::string m_parentNodeName;
90 Nodes m_children;
91 Type m_type = Type::None;
92
93 public:
94 19 static std::string escapeXml(const std::string &vDatas) {
95
1/1
✓ Call 0 invoked.
19 std::string escaped = vDatas;
96
3/3
✓ Branch 1 taken 19 times.
✓ Branch 4 taken 19 times.
✓ Branch 7 taken 19 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
76 replaceAll(escaped, "&", "&amp;");
97
3/3
✓ Branch 1 taken 19 times.
✓ Branch 4 taken 19 times.
✓ Branch 7 taken 19 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
76 replaceAll(escaped, "<", "&lt;");
98
3/3
✓ Branch 1 taken 19 times.
✓ Branch 4 taken 19 times.
✓ Branch 7 taken 19 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
76 replaceAll(escaped, "\"", "&quot;");
99
3/3
✓ Branch 1 taken 19 times.
✓ Branch 4 taken 19 times.
✓ Branch 7 taken 19 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
76 replaceAll(escaped, "'", "&apos;");
100
3/3
✓ Branch 1 taken 19 times.
✓ Branch 4 taken 19 times.
✓ Branch 7 taken 19 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
57 replaceAll(escaped, ">", "&gt;");
101 19 return escaped;
102 }
103
104 // replace xml excaped pattern by corresponding good pattern
105 static std::string unEscapeXml(const std::string &vDatas) {
106 std::string unescaped = vDatas;
107 replaceAll(unescaped, "&lt;", "<");
108 replaceAll(unescaped, "&amp;", "&");
109 replaceAll(unescaped, "&quot;", "\"");
110 replaceAll(unescaped, "&apos;", "'");
111 replaceAll(unescaped, "&gt;", ">");
112 return unescaped;
113 }
114
115 95 static void replaceAll(std::string &vStr, const std::string &vFrom, const std::string &vTo) {
116
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 95 times.
1/1
✓ Call 0 invoked.
95 if (vFrom.empty()) return;
117 95 size_t startPos = 0;
118
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 95 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 95 times.
1/1
✓ Call 0 invoked.
99 while ((startPos = vStr.find(vFrom, startPos)) != std::string::npos) {
119
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
4 vStr.replace(startPos, vFrom.length(), vTo);
120
1/1
✓ Call 0 invoked.
4 startPos += vTo.length();
121 }
122 }
123
124 public:
125
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
20 Node(const std::string &vName = "") : m_name(vName) {
126 20 }
127
128 Node &setName(const std::string &vName) {
129
0/1
✗ Call 0 not invoked.
m_name = vName;
130 return *this;
131 }
132
133 16 Node &addChild(const Node &vChild) {
134
1/1
✓ Call 0 invoked.
16 m_children.push_back(vChild);
135
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
16 m_children.back().m_setParentNodeName(getName());
136
1/1
✓ Call 0 invoked.
16 return m_children.back();
137 }
138
139 Node &addChild(const std::string &vName) {
140
0/1
✗ Call 0 not invoked.
Node node(vName);
141
0/1
✗ Call 0 not invoked.
return addChild(node);
142 }
143
144 Node &addComment(const std::string &vComment) {
145
0/4
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
Node node;
146
0/2
✗ Call 0 not invoked.
✗ Call 3 not invoked.
node.setContent(vComment).m_setType(Type::Comment);
147
0/1
✗ Call 0 not invoked.
return addChild(node);
148 }
149
150 Node *getChild(const std::string &vName) {
151 for (auto &child: m_children) {
152 if (child.m_name == vName) {
153 return &child;
154 }
155 }
156 return nullptr;
157 }
158
159 Node &getOrAddChild(const std::string &vName) {
160 Node *ret = getChild(vName);
161 if (ret == nullptr) {
162 ret = &addChild(vName);
163 }
164 return *ret;
165 }
166
167 Node &addChilds(const Nodes &vChilds) {
168 for (const auto &node: vChilds) {
169 addChild(node);
170 }
171 return *this;
172 }
173 template<typename T>
174 Node& addAttribute(const std::string& vKey, const T& vValue) {
175
0/1
✗ Call 0 not invoked.
std::stringstream ss;
176
0/1
✗ Call 0 not invoked.
ss << vValue;
177
0/8
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 9 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
m_attributes[vKey] = Attribute(ss.str());
178 return *this;
179 }
180
181 Attribute& addAttribute(const std::string& vKey) {
182
0/5
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
m_attributes[vKey] = Attribute();
183
0/1
✗ Call 0 not invoked.
return m_attributes[vKey];
184 }
185
186 1 bool isAttributeExist(const std::string &vKey) const {
187
1/1
✓ Branch 2 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
1 return (m_attributes.find(vKey) != m_attributes.end());
188 }
189
190 template<typename T = std::string>
191 24 T getAttribute(const std::string &vKey) const {
192
1/1
✓ Call 0 invoked.
22 T ret;
193
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
24 std::stringstream ss;
194
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
24 auto it = m_attributes.find(vKey);
195
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 12 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
24 if (it != m_attributes.end()) {
196
1/1
✓ Branch 2 taken 12 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
24 ss << it->second;
197 }
198
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
24 ss >> ret;
199 46 return ret;
200
1/3
✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
24 }
201
202 template<typename T>
203 Node &setContent(const T &vContent) {
204
0/1
✗ Call 0 not invoked.
std::stringstream ss;
205
0/1
✗ Call 0 not invoked.
ss << vContent;
206
0/3
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
m_content = ss.str();
207 return *this;
208 }
209
210 7 Node &setContent(const std::string &vContent) {
211
1/1
✓ Call 0 invoked.
7 m_content = vContent;
212 7 return *this;
213 }
214
215 // specific case for std::string
216 template <typename T = std::string>
217 22 typename std::enable_if<std::is_same<T, std::string>::value, T>::type getContent() const {
218
1/1
✓ Call 0 invoked.
22 return m_content;
219 }
220
221 // specific case for bool
222 template <typename T>
223 2 typename std::enable_if<std::is_same<T, bool>::value, T>::type getContent() const {
224
1/1
✓ Call 0 invoked.
2 return (m_content == "true");
225 }
226
227 // general cases (exclude std::string and bool)
228 template <typename T>
229 typename std::enable_if<!std::is_same<T, std::string>::value && !std::is_same<T, bool>::value, T>::type getContent() const {
230 T ret;
231 std::stringstream ss;
232 ss << m_content;
233 ss >> ret;
234 return ret;
235 }
236
237 11 Nodes &getChildren() { return m_children; }
238
239 22 const Nodes &getChildren() const { return m_children; }
240
241 1 const std::string &getParentNodeName() const {
242 1 return m_parentNodeName;
243 }
244
245 51 const std::string &getName() const {
246 51 return m_name;
247 }
248
249 19 std::string dump(const xml::Node &vNode, const uint32_t vLevel = 0) const {
250
1/1
✓ Branch 1 taken 19 times.
1/1
✓ Call 0 invoked.
19 std::string indent(vLevel * 2, ' '); // Indentation based on the depth level
251
1/1
✓ Branch 1 taken 19 times.
1/1
✓ Call 0 invoked.
19 std::ostringstream oss;
252
253
1/1
✓ Branch 1 taken 19 times.
1/1
✓ Call 0 invoked.
19 oss << indent;
254
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
19 if (vNode.m_getType() != xml::Node::Type::Comment) {
255
2/2
✓ Branch 1 taken 17 times.
✓ Branch 5 taken 17 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
17 oss << "<" << vNode.getName();
256
2/2
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 17 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 17 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
29 for (const auto &attr: vNode.m_attributes) {
257
6/6
✓ Branch 1 taken 12 times.
✓ Branch 4 taken 12 times.
✓ Branch 7 taken 12 times.
✓ Branch 11 taken 12 times.
✓ Branch 14 taken 12 times.
✓ Branch 17 taken 12 times.
9/10
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 16 invoked.
✓ Call 19 invoked.
✓ Call 20 invoked.
✗ Call 21 not invoked.
12 oss << " " << attr.first << "=\"" << xml::Node::escapeXml(attr.second.getValue()) << "\"";
258 }
259 } else {
260
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 oss << "<!-- ";
261 }
262
263
1/1
✓ Branch 1 taken 19 times.
1/1
✓ Call 0 invoked.
19 const auto &content = vNode.getContent();
264
1/1
✓ Call 0 invoked.
19 const auto &children = vNode.getChildren();
265
266
6/6
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 7 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 12 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 12 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
19 if (content.empty() && children.empty()) {
267
2/2
✓ Branch 1 taken 7 times.
✓ Branch 4 taken 7 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
7 oss << "/>" << std::endl;
268 } else {
269
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
12 if (vNode.m_getType() != xml::Node::Type::Comment) {
270
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 oss << ">";
271 }
272
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 5 times.
1/1
✓ Call 0 invoked.
12 if (!content.empty()) {
273
2/2
✓ Branch 1 taken 7 times.
✓ Branch 4 taken 7 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
7 oss << xml::Node::escapeXml(content);
274 }
275
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 10 times.
1/1
✓ Call 0 invoked.
12 if (vNode.m_getType() == xml::Node::Type::Comment) {
276
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
2 oss << " -->" << std::endl;
277 }
278
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 5 times.
1/1
✓ Call 0 invoked.
12 if (!children.empty()) {
279
1/1
✓ Branch 1 taken 7 times.
1/1
✓ Call 0 invoked.
7 oss << std::endl;
280
2/2
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 7 times.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 7 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
23 for (const auto &child: children) {
281
2/2
✓ Branch 1 taken 16 times.
✓ Branch 4 taken 16 times.
4/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
16 oss << dump(child, vLevel + 1);
282 }
283
1/1
✓ Branch 1 taken 7 times.
1/1
✓ Call 0 invoked.
7 oss << indent;
284 }
285
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
12 if (vNode.m_getType() != xml::Node::Type::Comment) {
286
4/4
✓ Branch 1 taken 10 times.
✓ Branch 5 taken 10 times.
✓ Branch 8 taken 10 times.
✓ Branch 11 taken 10 times.
5/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
10 oss << "</" << vNode.getName() << ">" << std::endl;
287 }
288 }
289
290
1/1
✓ Branch 1 taken 19 times.
1/1
✓ Call 0 invoked.
38 return oss.str();
291
3/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
19 }
292
293 3 std::string dump() const {
294
1/1
✓ Call 0 invoked.
3 return dump(*this);
295 }
296
297 private:
298
299 12 void m_setAttribute(const std::string &vKey, const std::string &vValue) {
300
2/2
✓ Branch 1 taken 12 times.
✓ Branch 4 taken 12 times.
4/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
12 m_attributes[vKey] = Attribute(vValue);
301 12 }
302
303 19 void m_setType(Type vType) {
304 19 m_type = vType;
305 19 }
306
307 55 Type m_getType() const {
308 55 return m_type;
309 }
310
311 16 void m_setParentNodeName(const std::string &vName) {
312
1/1
✓ Call 0 invoked.
16 m_parentNodeName = vName;
313 16 }
314 };
315
316 template<>
317 inline Node &Node::setContent(const bool &vContent) {
318 m_content = vContent ? "true" : "false";
319 return *this;
320 }
321
322 #if __cplusplus >= 201703L // c++17
323 template <>
324 inline bool Node::getContent<bool>() const {
325 return (m_content == "true");
326 }
327 #endif
328
329 } // namespace xml
330
331 class Xml {
332 private:
333 xml::Node m_Root;
334 // just during parsing,
335 // for know what is the current node
336 std::stack<xml::Node *> m_NodeStack;
337 enum class TokenType { //
338 OPENED = 0,
339 CLOSED,
340 OPENED_CLOSED,
341 COMMENT,
342 CONTENT,
343 Count
344 };
345
346 public:
347
1/1
✓ Branch 2 taken 3 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 Xml(const std::string &vRootName = "root") : m_Root(vRootName) {
348
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 m_NodeStack.push(&m_Root);
349
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
3 }
350
351 2 xml::Node &getRoot() {
352 2 return m_Root;
353 }
354
355 bool parseFile(const std::string &vFilePathName) {
356 std::ifstream docFile(vFilePathName, std::ios::in);
357 if (docFile.is_open()) {
358 std::stringstream strStream;
359 strStream << docFile.rdbuf(); // read the file
360 auto xml_content = strStream.str();
361 m_replaceString(xml_content, "\r\n", "\n");
362 m_replaceString(xml_content, "\r", "\n");
363 docFile.close();
364 return parseString(xml_content);
365 }
366 return false;
367 }
368
369 3 bool parseString(const std::string &vDoc) {
370
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 auto tokens = m_tokenize(vDoc);
371
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
3 if (tokens.empty()) {
372 return false;
373 }
374
2/2
✓ Branch 5 taken 48 times.
✓ Branch 6 taken 2 times.
2/2
✓ Decision 'true' taken 48 times.
✓ Decision 'false' taken 2 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
50 for (const auto &token: tokens) {
375
1/1
✓ Call 0 invoked.
48 std::string tagName;
376
1/1
✓ Call 0 invoked.
48 std::map<std::string, std::string> attributes;
377
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 48 times.
1/1
✓ Call 0 invoked.
48 if (token.first.empty()) {
378 continue;
379 }
380
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 42 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 42 times.
48 if (token.second == TokenType::CLOSED) {
381
1/1
✓ Call 0 invoked.
6 m_NodeStack.pop();
382
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 9 times.
2/2
✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 25 times.
42 } else if (token.second == TokenType::OPENED || //
383
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 6 times.
33 token.second == TokenType::OPENED_CLOSED || //
384
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 25 times.
27 token.second == TokenType::COMMENT) {
385
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 2 times.
17 if (token.second != TokenType::COMMENT) {
386
1/1
✓ Branch 1 taken 15 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
15 tagName = m_extractTagName(token.first);
387 }
388
1/1
✓ Branch 1 taken 17 times.
1/1
✓ Call 0 invoked.
17 xml::Node newNode(tagName);
389
1/1
✓ Call 0 invoked.
17 newNode.m_setType(xml::Node::Type::Token);
390
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 15 times.
17 if (token.second == TokenType::COMMENT) {
391
1/1
✓ Call 0 invoked.
2 newNode.m_setType(xml::Node::Type::Comment);
392
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 newNode.setContent(token.first);
393 } else {
394
3/3
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 14 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 14 times.
1/1
✓ Call 0 invoked.
15 if (!m_extractAttributes(tagName, token.first, attributes)) {
395 1 return false;
396 }
397
2/2
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 14 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 14 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
26 for (const auto &kv: attributes) {
398
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
12 newNode.m_setAttribute(kv.first, kv.second);
399 }
400 }
401
1/1
✓ Branch 2 taken 16 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
16 m_NodeStack.top()->addChild(newNode);
402
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 7 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 7 times.
16 if (token.second == TokenType::OPENED) {
403
1/1
✓ Branch 4 taken 9 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
9 m_NodeStack.push(const_cast<xml::Node *>(&m_NodeStack.top()->getChildren().back()));
404 }
405
3/4
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
2/2
✓ Decision 'true' taken 25 times.
✓ Decision 'false' taken 33 times.
1/2
✓ Call 0 invoked.
✗ Call 5 not invoked.
58 } else if (token.second == TokenType::CONTENT) {
406
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 25 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
25 if (!m_NodeStack.empty()) {
407
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 20 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 20 times.
1/1
✓ Call 0 invoked.
25 if (token.first[0] != '\n') {
408
1/1
✓ Branch 2 taken 5 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
5 m_NodeStack.top()->setContent(token.first);
409 }
410 }
411 }
412
2/4
✓ Call 0 invoked.
✓ Call 4 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
49 }
413 2 return true;
414
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
3 }
415
416 3 std::string dump() const {
417
1/1
✓ Call 0 invoked.
3 return m_Root.dump();
418 }
419
420 private:
421 bool m_replaceString(std::string &str, const std::string &oldStr, const std::string &newStr) {
422 bool found = false;
423 size_t pos = 0;
424 while ((pos = str.find(oldStr, pos)) != std::string::npos) {
425 found = true;
426 str.replace(pos, oldStr.length(), newStr);
427 pos += newStr.length();
428 }
429 return found;
430 }
431
432 3 std::vector<std::pair<std::string, TokenType>> m_tokenize(const std::string &vDoc) {
433
1/1
✓ Call 0 invoked.
3 std::vector<std::pair<std::string, TokenType>> tokens;
434 3 size_t pos = 0;
435
1/1
✓ Call 0 invoked.
3 size_t length = vDoc.length();
436 3 TokenType type = TokenType::Count;
437
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 51 times.
✓ Decision 'false' taken 3 times.
54 while (pos < length) {
438
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 27 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 27 times.
1/1
✓ Call 0 invoked.
51 if (vDoc[pos] == '<') {
439 24 type = TokenType::OPENED;
440
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 17 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 17 times.
1/1
✓ Call 0 invoked.
24 if (vDoc[pos + 1] == '/') {
441 7 type = TokenType::CLOSED;
442
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 15 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 15 times.
1/1
✓ Call 0 invoked.
17 } else if (vDoc[pos + 1] == '!') {
443 2 type = TokenType::COMMENT;
444 }
445
1/1
✓ Call 0 invoked.
24 size_t end = vDoc.find(">", pos);
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 24 times.
24 if (end == std::string::npos) {
447 break;
448 }
449
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 18 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 18 times.
1/1
✓ Call 0 invoked.
24 if (vDoc[end - 1] == '/') {
450 6 type = TokenType::OPENED_CLOSED;
451 }
452
1/1
✓ Branch 1 taken 24 times.
1/1
✓ Call 0 invoked.
24 const auto ss = vDoc.substr(pos, end + 1 - pos);
453
2/2
✓ Branch 1 taken 24 times.
✓ Branch 4 taken 24 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
24 tokens.push_back(std::make_pair(ss, type));
454 24 pos = end + 1;
455
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
24 } else {
456
1/1
✓ Call 0 invoked.
27 size_t end = vDoc.find('<', pos);
457
1/1
✓ Branch 1 taken 27 times.
1/1
✓ Call 0 invoked.
27 const auto ss = vDoc.substr(pos, end - pos);
458
2/2
✓ Branch 1 taken 27 times.
✓ Branch 4 taken 27 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
27 tokens.push_back(std::make_pair(ss, TokenType::CONTENT));
459 27 pos = end;
460
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
27 }
461 }
462 6 return tokens;
463 }
464
465 15 std::string m_extractTagName(const std::string &vLine) {
466
1/1
✓ Call 0 invoked.
15 std::string ret;
467
1/1
✓ Call 0 invoked.
15 size_t startPos = vLine.find('<') + 1;
468
6/7
✓ Branch 1 taken 16 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 15 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 15 times.
0/1
? Decision couldn't be analyzed.
2/2
✓ Call 0 invoked.
✓ Call 5 invoked.
16 while (vLine.at(startPos) == ' ' && vLine.size() > startPos) {
469 1 ++startPos;
470 }
471
1/1
✓ Call 0 invoked.
15 size_t endPos = vLine.find_first_of(" \t>", startPos);
472
1/1
✓ Branch 1 taken 15 times.
1/1
✓ Call 0 invoked.
30 return vLine.substr(startPos, endPos - startPos);
473
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
15 }
474
475 // will remove space outside of <> and ""
476 std::string m_trim1(const std::string &vToken) {
477 std::string res;
478 int32_t scope = 0;
479 for (const auto c: vToken) {
480 if (scope == 1) {
481 res += c;
482 } else if (c == '"') {
483 if (scope == 0) {
484 ++scope;
485 } else {
486 --scope;
487 }
488 }
489 }
490 return res;
491 }
492
493 // will remove spaces from start and from end
494 // if the token is like tk0 tk1 tk2, only tk0 will be returned
495 14 std::string m_trim2(const std::string &vToken) {
496
1/1
✓ Call 0 invoked.
14 std::string res;
497
2/2
✓ Branch 5 taken 72 times.
✓ Branch 6 taken 12 times.
2/2
✓ Decision 'true' taken 72 times.
✓ Decision 'false' taken 12 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
84 for (const auto c: vToken) {
498
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 70 times.
✓ Decision 'false' taken 2 times.
72 if (c != ' ') {
499
1/1
✓ Branch 1 taken 70 times.
1/1
✓ Call 0 invoked.
70 res += c;
500
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
2 } else if (!res.empty()) {
501 2 break;
502 }
503 }
504 14 return res;
505 }
506
507 15 bool m_extractAttributes(const std::string &vTagName, const std::string &vLine,
508 std::map<std::string, std::string> &attributes) {
509
1/1
✓ Call 0 invoked.
15 size_t startPos = vLine.find(vTagName);
510
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 15 times.
✗ Decision 'false' not taken.
15 if (startPos != std::string::npos) {
511
1/1
✓ Call 0 invoked.
15 startPos += vTagName.size();
512
1/1
✓ Call 0 invoked.
15 startPos = vLine.find(' ', startPos);
513
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 13 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 13 times.
28 while (startPos != std::string::npos) {
514
1/1
✓ Call 0 invoked.
15 startPos = vLine.find_first_not_of(" \t", startPos);
515
3/3
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 14 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 14 times.
1/1
✓ Call 0 invoked.
15 if (vLine.at(startPos) == '>') {
516 1 break;
517 }
518
1/1
✓ Call 0 invoked.
14 size_t equalsPos = vLine.find('=', startPos);
519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 14 times.
14 if (equalsPos == std::string::npos) {
520 1 return false;
521 }
522
2/2
✓ Branch 1 taken 14 times.
✓ Branch 4 taken 14 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
14 std::string key = m_trim2(vLine.substr(startPos, equalsPos - startPos));
523 14 startPos = equalsPos + 1;
524
1/1
✓ Call 0 invoked.
14 char quoteChar = vLine[startPos];
525
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 14 times.
16 while (quoteChar == ' ') {
526
1/1
✓ Call 0 invoked.
2 quoteChar = vLine[++startPos];
527 }
528
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 13 times.
✓ Decision 'false' taken 1 times.
14 if (quoteChar == '"' || quoteChar == '\'') {
529 13 startPos++;
530
1/1
✓ Call 0 invoked.
13 size_t endPos = vLine.find(quoteChar, startPos);
531
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 13 times.
✗ Decision 'false' not taken.
13 if (endPos != std::string::npos) {
532
1/1
✓ Branch 1 taken 13 times.
1/1
✓ Call 0 invoked.
13 std::string value = vLine.substr(startPos, endPos - startPos);
533
2/2
✓ Branch 1 taken 13 times.
✓ Branch 4 taken 13 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
13 attributes[key] = value;
534
1/1
✓ Call 0 invoked.
13 startPos = vLine.find(' ', endPos); // Passer ? l'attribut suivant
535
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
13 } else {
536 #ifdef LogVarError
537 LogVarError("The attribut '%s' have invalid value", key.c_str());
538 #endif
539 return false; // Erreur : guillemets/apostrophes non ferm?s
540 }
541 13 } else {
542 #ifdef LogVarError
543 LogVarError("The attribut '%s' have invalid value", key.c_str());
544 #endif
545 1 return false; // Erreur : attribut sans guillemets ou apostrophes
546 }
547
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
14 }
548 14 return true;
549 }
550 return false;
551 }
552 };
553
554 } // namespace ez
555

Directory: include/ezlibs/
File: ezGL/uniforms.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 135 141 95.7%
Functions: 6 6 100.0%
Branches: 146 201 72.6%
Decisions: 16 20 80.0%
Calls: 168 210 80.0%
Line Branch Decision Call Exec Source
1 /*
2 MIT License
3
4 Copyright (c) 2014-2023 Stephane Cuillerdier (aka aiekick)
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24
25 #pragma once
26
27 /*
28 * this class will manage uniforms
29 * will parse a code and filter uniforms code
30 * uniform widgets
31 *
32 */
33
34 #include <map>
35 #include <string>
36 #include <cassert>
37 #include <fstream>
38 #include <functional>
39 #include <unordered_map>
40
41 namespace ez {
42 namespace gl {
43
44 class UniformParsingDatas {
45 public:
46 std::string uniform_line;
47 std::string uniform_type;
48 std::string widget_type;
49 std::string uniform_name;
50 std::string uniform_comment; // les \\n serait remaplce par des \n pour affichage
51 std::string uniform_comment_original; // les \\n reste des \\n
52 std::string uniform_param_line;
53 std::vector<std::string> params;
54 bool valid = false;
55
56 public:
57 UniformParsingDatas() = default;
58
8/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
23 UniformParsingDatas(const std::string& vUniformString) {
59
1/1
✓ Branch 1 taken 23 times.
1/1
✓ Call 0 invoked.
23 valid = m_ParseUniformString(vUniformString);
60
0/8
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
23 }
61 std::string getFinalUniformCode() const {
62 if (uniform_comment_original.empty()) {
63 return "uniform " + uniform_type + " " + uniform_name + ";";
64 } else {
65 return "uniform " + uniform_type + " " + uniform_name + "; // " + uniform_comment_original;
66 }
67 }
68 23 bool isValid() const {
69 23 return valid;
70 }
71
72 private:
73 44 size_t m_IgnoreComments(const std::string& vUniformString, const size_t& vPos) {
74
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 42 times.
✓ Decision 'false' taken 2 times.
44 if (vPos != std::string::npos) {
75
1/1
✓ Call 0 invoked.
42 char c = vUniformString[vPos];
76
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 16 times.
2/2
✓ Decision 'true' taken 26 times.
✓ Decision 'false' taken 16 times.
42 if (c == '/' || c == ' ') {
77
1/1
✓ Call 0 invoked.
26 auto next_space = vUniformString.find_first_of(" /", vPos);
78
1/1
✓ Call 0 invoked.
26 auto start_pos = vUniformString.find("/*", vPos);
79
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 24 times.
26 if (next_space >= start_pos) {
80
1/1
✓ Call 0 invoked.
2 auto start_not_pos = vUniformString.find("*/", vPos);
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
2 if (start_not_pos < start_pos) {
82 return vPos;
83 }
84
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2 if (start_pos != std::string::npos) {
85
1/1
✓ Call 0 invoked.
2 auto end_pos = vUniformString.find("*/", start_pos);
86
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2 if (end_pos != std::string::npos) {
87 2 end_pos += 2;
88 2 return end_pos;
89 }
90 }
91 }
92 }
93 }
94 42 return vPos;
95 }
96 23 bool m_ParseUniformString(const std::string& vUniformString) {
97
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 22 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 22 times.
1/1
✓ Call 0 invoked.
23 if (vUniformString.empty()) {
98 1 return false;
99 }
100
101
1/1
✓ Branch 1 taken 22 times.
1/1
✓ Call 0 invoked.
22 uniform_line = vUniformString;
102
103 // we wnat to get all theses
104 // uniform type(widget:params) name; comment
105
106 22 bool uniform_found = false;
107 22 bool type_found = false;
108 22 bool name_found = false;
109
110
1/1
✓ Call 0 invoked.
22 auto first_comment = vUniformString.find("//");
111
1/1
✓ Call 0 invoked.
22 auto pos = vUniformString.find("uniform");
112
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 20 times.
22 if (first_comment != std::string::npos && first_comment < pos) {
113 2 return false;
114 }
115
116
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 2 times.
20 if (first_comment > pos && pos != std::string::npos) {
117 18 uniform_found = true;
118
1/1
✓ Branch 1 taken 18 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
18 pos += std::string("uniform").size();
119
120
1/1
✓ Call 0 invoked.
18 pos = m_IgnoreComments(vUniformString, pos);
121
122 // type and params
123
1/1
✓ Call 0 invoked.
18 auto type_pos = vUniformString.find_first_of("abcdefghijklmnopqrstuvwxyz(", pos);
124
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 18 times.
✗ Decision 'false' not taken.
18 if (type_pos != std::string::npos) {
125
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
1/1
✓ Call 0 invoked.
18 if (vUniformString[type_pos] == '(') {
126 return (uniform_found && type_found && name_found);
127 }
128 // pos = type_pos;
129
1/1
✓ Call 0 invoked.
18 size_t first_parenthesis_pos = vUniformString.find('(', type_pos + 1);
130
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
18 if (first_parenthesis_pos != std::string::npos) {
131 6 first_parenthesis_pos += 1;
132
1/1
✓ Branch 1 taken 6 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
6 uniform_type = vUniformString.substr(type_pos, first_parenthesis_pos - (type_pos + 1));
133
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
6 if (!uniform_type.empty()) {
134 6 type_found = true;
135 }
136
1/1
✓ Call 0 invoked.
6 first_parenthesis_pos = m_IgnoreComments(vUniformString, first_parenthesis_pos);
137
1/1
✓ Call 0 invoked.
6 size_t last_parenthesis_pos = vUniformString.find_first_of("()", first_parenthesis_pos);
138
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (last_parenthesis_pos != std::string::npos) {
139
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
6 if (vUniformString[last_parenthesis_pos] == ')') {
140
1/1
✓ Branch 1 taken 6 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
6 uniform_param_line = vUniformString.substr(first_parenthesis_pos, last_parenthesis_pos - first_parenthesis_pos);
141 6 pos = last_parenthesis_pos + 1;
142 } else {
143 return (uniform_found && type_found && name_found);
144 }
145 } else {
146 return (uniform_found && type_found && name_found);
147 }
148 } else {
149
1/1
✓ Call 0 invoked.
12 size_t nextSpace = vUniformString.find_first_of(" /", type_pos + 1);
150
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (nextSpace != std::string::npos) {
151
1/1
✓ Branch 1 taken 11 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
11 uniform_type = vUniformString.substr(type_pos, nextSpace - type_pos);
152
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
11 if (!uniform_type.empty()) {
153 11 type_found = true;
154 }
155
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 times.
1/1
✓ Call 0 invoked.
11 if (vUniformString[nextSpace] == ' ') {
156 10 pos = nextSpace + 1;
157 }
158
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10 times.
1/1
✓ Call 0 invoked.
11 if (vUniformString[nextSpace] == '/') {
159 1 pos = nextSpace;
160 }
161 }
162 }
163 }
164 }
165
166 // name
167
1/1
✓ Call 0 invoked.
20 pos = m_IgnoreComments(vUniformString, pos);
168
1/1
✓ Call 0 invoked.
20 size_t coma_pos = vUniformString.find_first_of(";\n\r/[", pos);
169
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 3 times.
20 if (coma_pos != std::string::npos) {
170
1/1
✓ Call 0 invoked.
17 size_t namePos = vUniformString.find_first_of("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", pos);
171
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
17 if (namePos != std::string::npos) {
172
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
16 if (namePos < coma_pos) {
173
1/1
✓ Branch 1 taken 15 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
15 uniform_name = vUniformString.substr(namePos, coma_pos - namePos);
174
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
45 m_replace_string(uniform_name, " ", "_");
175
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
15 if (!uniform_type.empty()) {
176 15 name_found = true;
177 }
178 }
179 }
180
181
5/8
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 14 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
17 if (vUniformString[coma_pos] != ';' && vUniformString[coma_pos] != '[' && vUniformString[coma_pos] != '/') {
182 return (uniform_found && type_found && name_found);
183 }
184 } else {
185
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
3 return (uniform_found && type_found && name_found);
186 }
187
188
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 15 times.
1/1
✓ Call 0 invoked.
17 if (uniform_name.empty()) {
189
4/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 return (uniform_found && type_found && name_found);
190 }
191
192 // array
193 /*size_t arrayPos = vUniformString.find_first_of('[');
194 if (arrayPos != std::string::npos) {
195 arrayPos += 1;
196 size_t endArray = vUniformString.find_first_of("[]", arrayPos);
197 if (endArray != std::string::npos) {
198 if (vUniformString[endArray] == ']') {
199 array = vUniformString.substr(arrayPos, endArray - arrayPos);
200 pos = endArray + 1;
201 } else {
202 return (uniform_found && type_found && name_found);
203 }
204 } else {
205 return (uniform_found && type_found && name_found);
206 }
207 }*/
208
209 // comment
210
1/1
✓ Call 0 invoked.
15 coma_pos = vUniformString.find_first_of(";\n\r");
211
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (coma_pos != std::string::npos) {
212
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
15 if (vUniformString[coma_pos] == ';') {
213 15 coma_pos += 1;
214
1/1
✓ Branch 1 taken 15 times.
1/1
✓ Call 0 invoked.
15 std::string afterComaStr = vUniformString.substr(coma_pos);
215
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 7 times.
1/1
✓ Call 0 invoked.
15 if (!afterComaStr.empty()) {
216
1/1
✓ Call 0 invoked.
8 size_t uniform_comment_pos = afterComaStr.find("//");
217
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (uniform_comment_pos == std::string::npos) {
218
1/1
✓ Call 0 invoked.
6 uniform_comment_pos = afterComaStr.find("/*");
219 }
220
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (uniform_comment_pos != std::string::npos) {
221 8 uniform_comment_pos += 2;
222
1/1
✓ Branch 1 taken 8 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
8 uniform_comment_original = afterComaStr.substr(uniform_comment_pos);
223
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
24 m_replace_string(uniform_comment_original, "*/", ""); // win
224
1/1
✓ Branch 1 taken 8 times.
1/1
✓ Call 0 invoked.
8 uniform_comment = uniform_comment_original;
225
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
32 m_replace_string(uniform_comment, "\\n", "\n"); // win
226
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
32 m_replace_string(uniform_comment, "\\r", "\r"); // unix
227 }
228 }
229
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
15 } else {
230 return (uniform_found && type_found && name_found);
231 }
232 }
233
234
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_type, " ", "");
235
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(widget_type, " ", "");
236
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_name, " ", "");
237
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_param_line, " ", "");
238
239
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_type, "\t", "");
240
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(widget_type, "\t", "");
241
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_name, "\t", "");
242
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_param_line, "\t", "");
243
244
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_type, "\r", "");
245
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(widget_type, "\r", "");
246
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
60 m_replace_string(uniform_name, "\r", "");
247
3/3
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
5/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
45 m_replace_string(uniform_param_line, "\r", "");
248
249 /// parse params
250
251
1/1
✓ Call 0 invoked.
15 std::string word;
252 15 bool first_word = true;
253
2/2
✓ Branch 5 taken 55 times.
✓ Branch 6 taken 15 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
70 for (auto c : uniform_param_line) {
254
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 7 times.
55 if (c != ':') {
255
1/1
✓ Branch 1 taken 48 times.
1/1
✓ Call 0 invoked.
48 word += c;
256 } else {
257
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (first_word) {
258
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
1/1
✓ Call 0 invoked.
3 if (m_is_content_string(word)) {
259
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 widget_type = word;
260 2 first_word = false;
261 } else {
262
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 widget_type = "slider";
263
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 params.push_back(word);
264 1 first_word = false;
265 }
266 } else {
267
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 params.push_back(word);
268 }
269
1/1
✓ Call 0 invoked.
7 word.clear();
270 }
271 }
272
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 9 times.
1/1
✓ Call 0 invoked.
15 if (!word.empty()) {
273
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (first_word) {
274
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
3 if (m_is_content_string(word)) {
275
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 widget_type = word;
276 }
277 } else {
278
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 params.push_back(word);
279 }
280 }
281
282
3/6
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
15 return (uniform_found && type_found && name_found);
283
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
15 }
284 219 bool m_replace_string(::std::string& vStr, const ::std::string& vOldStr, const ::std::string& vNewStr) {
285 219 bool found = false;
286 219 size_t pos = 0;
287
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 219 times.
1/1
✓ Call 0 invoked.
233 while ((pos = vStr.find(vOldStr, pos)) != ::std::string::npos) {
288 14 found = true;
289
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
14 vStr.replace(pos, vOldStr.length(), vNewStr);
290
1/1
✓ Call 0 invoked.
14 pos += vNewStr.length();
291 }
292 219 return found;
293 }
294 6 bool m_is_content_string(const std::string& vStr) {
295
1/1
✓ Call 0 invoked.
6 auto num_pos = vStr.find_first_of("0123456789.");
296
1/1
✓ Call 0 invoked.
6 auto str_pos = vStr.find_first_of("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
297 6 return (str_pos < num_pos);
298 }
299 };
300
301 /*
302 * class used for expsoe internal function of Uniforms class for test
303 */
304 class UniformStrings {
305 public:
306 // uniform pos, uniform line, uniform end
307 typedef std::unordered_map<size_t, UniformParsingDatas> UniformStringsContainer;
308
309 private:
310 UniformStringsContainer m_uniform_strings;
311
312 public:
313 std::string parse_and_filter_code(const std::string& vCode) {
314 std::string final_code = vCode;
315 auto _uniform_strings = m_get_uniform_strings(final_code);
316 if (!_uniform_strings.empty()) {
317 final_code = m_filter_code(final_code, _uniform_strings);
318 }
319 return final_code;
320 }
321 const UniformStringsContainer& get_uniform_strings() {
322 return m_uniform_strings;
323 }
324 UniformStringsContainer& get_uniforms_strings_ref() {
325 return m_uniform_strings;
326 }
327
328 protected:
329 UniformStringsContainer m_get_uniform_strings(const std::string& vCode) {
330 UniformStringsContainer res;
331 size_t uniform_pos = 0U;
332 while (uniform_pos != std::string::npos) {
333 uniform_pos = vCode.find("uniform", uniform_pos);
334 if (uniform_pos != std::string::npos) {
335 size_t end_line_pos = vCode.find_first_of("\n\r", uniform_pos);
336 if (end_line_pos != std::string::npos) {
337 auto uniform_line = vCode.substr(uniform_pos, end_line_pos - uniform_pos);
338 res[uniform_pos] = UniformParsingDatas(uniform_line);
339 uniform_pos = end_line_pos;
340 }
341 ++uniform_pos;
342 }
343 }
344 return res;
345 }
346
347 // will replace bad glsl uniform code (code with declarative uniform syntax) to good uniform code
348 std::string m_filter_code(const std::string& vCode, const UniformStringsContainer& vContainer) {
349 std::string final_code = vCode;
350 size_t offset = 0;
351 for (auto _uniform_datas : vContainer) {
352 const auto& datas = _uniform_datas.second;
353 if (!datas.widget_type.empty()) {
354 const auto& uniform_code = datas.getFinalUniformCode();
355 size_t pos = _uniform_datas.first - offset;
356 final_code.replace(pos, datas.uniform_line.size(), uniform_code);
357 offset += datas.uniform_line.size() - uniform_code.size(); // le nouveau code sera forcemment plus court
358 assert(offset != std::string::npos);
359 }
360 }
361 #ifdef _DEBUG
362 m_save_string_to_file(final_code, "debug/shader.glsl");
363 #endif
364 return final_code;
365 }
366
367 #ifdef _DEBUG
368 void m_save_string_to_file(const std::string& vString, const std::string& vFilePathName) {
369 std::ofstream fileWriter(vFilePathName, std::ios::out);
370 if (!fileWriter.bad()) {
371 fileWriter << vString;
372 fileWriter.close();
373 }
374 }
375 #endif
376 };
377
378 class IUniform {
379 public:
380 typedef std::function<bool(IUniform*)> IUniformDrawWidgetFunctor;
381
382 protected:
383 std::string m_name;
384 GLint m_loc = -1;
385 GLuint m_channels = 1U;
386 bool m_used = false;
387 bool m_showed = false;
388 std::string m_type;
389 std::string m_widget;
390 IUniformDrawWidgetFunctor m_draw_widget_functor = nullptr;
391 UniformParsingDatas m_uniform_parsing_datas;
392
393 public:
394 void set_uniform_parsing_datas(const UniformParsingDatas& vUniformParsingDatas) {
395 m_uniform_parsing_datas = vUniformParsingDatas;
396 }
397 void set_draw_widget_functor(const IUniformDrawWidgetFunctor& vUniformDrawWidgetFunctor) {
398 m_draw_widget_functor = vUniformDrawWidgetFunctor;
399 }
400 virtual bool draw_widget() {
401 if (m_draw_widget_functor != nullptr) {
402 return m_draw_widget_functor(this);
403 }
404 return true;
405 };
406 const char* get_general_help() {
407 return u8R"(
408 general syntax is :
409 - uniform type(widget:params) name; // simple or multiline comment
410 )";
411 }
412 virtual const char* get_help() {
413 return "";
414 };
415 virtual bool upload_sampler(int32_t& /*texture_slot_id*/) {
416 return false;
417 };
418 virtual bool upload_scalar() {
419 return false;
420 };
421 };
422
423 class UniformTime : public IUniform {
424 private:
425 bool m_play = false;
426 float m_time = 0.0f;
427
428 public:
429 bool upload_scalar() override {
430 if (m_loc > 0) {
431 glUniform1fv(m_loc, 1, &m_time);
432 CheckGLErrors;
433 return true;
434 }
435 return false;
436 }
437 void play(bool vFlag) {
438 m_play = vFlag;
439 }
440 const char* get_help() override {
441 return u8R"(
442 buffer uniform syantax :(default is optional)
443 - uniform float(time:default) name;
444 )";
445 }
446 };
447
448 class UniformBuffer : public IUniform {
449 private:
450 std::array<float, 3U> m_size = {};
451 int32_t m_sampler2D = -1; // sampler2D
452
453 public:
454 UniformBuffer() {
455 m_widget = "buffer";
456 }
457 bool upload_scalar() override {
458 if (m_loc > 0) {
459 switch (m_channels) {
460 case 2U: glUniform2fv(m_loc, 1, m_size.data()); break;
461 case 3U: glUniform3fv(m_loc, 1, m_size.data()); break;
462 }
463 CheckGLErrors;
464 return true;
465 }
466 return false;
467 }
468 bool upload_sampler(int32_t& texture_slot_id) override {
469 if (m_loc > 0) {
470 glActiveTexture(GL_TEXTURE0 + texture_slot_id);
471 CheckGLErrors;
472 glBindTexture(GL_TEXTURE_2D, m_sampler2D);
473 CheckGLErrors;
474 glUniform1i(m_loc, texture_slot_id);
475 CheckGLErrors;
476 ++texture_slot_id;
477 return true;
478 }
479 return false;
480 }
481 const char* get_help() override {
482 return u8R"(
483 buffer uniform syantax :
484 - resolution :
485 - vec2 resolution => uniform vec2(buffer) name;
486 - vec3 resolution => uniform vec2(buffer) name; (like shadertoy resolution)
487 - sampler2D back buffer : (target is optional. n is the fbo attachment id frrm 0 to 7)
488 - uniform sampler2D(buffer) name; => for target == 0
489 - uniform sampler2D(buffer:target=n) name; => for target == n
490 )";
491 }
492 };
493
494 class UniformSlider : public IUniform {
495 public:
496 const char* get_help() override {
497 return u8R"(
498 float slider uniform syntax : (default and step are otionals)
499 - uniform float(inf:sup:default:step) name;
500 - uniform vec2(inf:sup:default:step) name;
501 - uniform vec3(inf:sup:default:step) name;
502 - uniform vec4(inf:sup:default:step) name;
503 - uniform int(inf:sup:default:step) name;
504 - uniform ivec2(inf:sup:default:step) name;
505 - uniform ivec3(inf:sup:default:step) name;
506 - uniform ivec4(inf:sup:default:step) name;
507 )";
508 }
509 };
510 class UniformFloatSlider : public UniformSlider {
511 private:
512 std::array<float, 4U> m_datas_f;
513
514 public:
515 bool upload_scalar() override {
516 if (m_loc > 0) {
517 switch (m_channels) {
518 case 1U: glUniform2fv(m_loc, 1, m_datas_f.data()); break;
519 case 2U: glUniform2fv(m_loc, 1, m_datas_f.data()); break;
520 case 3U: glUniform3fv(m_loc, 1, m_datas_f.data()); break;
521 case 4U: glUniform2fv(m_loc, 1, m_datas_f.data()); break;
522 }
523 CheckGLErrors;
524 return true;
525 }
526 return false;
527 }
528 };
529
530 class UniformIntSlider : public UniformSlider {
531 private:
532 std::array<int32_t, 4U> m_datas_i;
533
534 public:
535 bool upload_scalar() override {
536 if (m_loc > 0) {
537 switch (m_channels) {
538 case 1U: glUniform2iv(m_loc, 1, m_datas_i.data()); break;
539 case 2U: glUniform2iv(m_loc, 1, m_datas_i.data()); break;
540 case 3U: glUniform3iv(m_loc, 1, m_datas_i.data()); break;
541 case 4U: glUniform2iv(m_loc, 1, m_datas_i.data()); break;
542 }
543 CheckGLErrors;
544 return true;
545 }
546 return false;
547 }
548 };
549
550 class UniformsManager : public UniformStrings {
551 public:
552 typedef std::map<std::string, IUniform*> UniformsContainer;
553
554 private:
555 UniformsContainer m_uniforms;
556
557 public:
558 const UniformsContainer& get_uniforms() {
559 return m_uniforms;
560 }
561 UniformsContainer& get_uniforms_ref() {
562 return m_uniforms;
563 }
564 };
565
566 } // namespace gl
567 } // namespace ez
568

Directory: include/ezlibs/
File: ezSha.hpp
Date: 2025-07-28 14:06:36
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 166 171 97.1%
Functions: 12 12 100.0%
Branches: 26 32 81.2%
Decisions: 22 30 73.3%
Calls: 262 263 99.6%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezSha is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28 // and base on https://github.com/983/SHA1.git - Unlicense
29
30 #include <cstdint>
31 #include <cstring>
32 #include <array>
33
34 namespace ez {
35
36 class sha1 {
37 public:
38 static size_t constexpr SHA1_HEX_SIZE{40 + 1};
39 static size_t constexpr SHA1_BASE64_SIZE{28 + 1};
40
41 private:
42 std::array<uint32_t, 5> m_state{};
43 std::array<uint8_t, 64> m_buf;
44 uint32_t m_index{};
45 uint64_t m_countBits{};
46
47 public:
48 1 sha1(const char *text = NULL) : m_index(0), m_countBits(0) {
49
1/1
✓ Call 0 invoked.
1 m_state[0] = 0x67452301;
50
1/1
✓ Call 0 invoked.
1 m_state[1] = 0xEFCDAB89;
51
1/1
✓ Call 0 invoked.
1 m_state[2] = 0x98BADCFE;
52
1/1
✓ Call 0 invoked.
1 m_state[3] = 0x10325476;
53
1/1
✓ Call 0 invoked.
1 m_state[4] = 0xC3D2E1F0;
54
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (text) {
55
1/1
✓ Call 0 invoked.
1 add(text);
56 }
57 1 }
58
59 43 sha1 &add(uint8_t x) {
60
1/1
✓ Call 0 invoked.
43 m_addByteDontCountBits(x);
61 43 m_countBits += 8;
62 43 return *this;
63 }
64
65
1/1
✓ Call 0 invoked.
1 sha1 &add(char c) { return add(*(uint8_t *)&c); }
66
67 3 sha1 &add(const void *data, uint32_t n) {
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
3 if (!data) {
69 return *this;
70 }
71
72 3 const uint8_t *ptr = (const uint8_t *)data;
73
74 // fill up block if not full
75
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 1 times.
0/1
? Decision couldn't be analyzed.
41 for (; n && m_index % sizeof(m_buf); n--)
76
1/1
✓ Call 0 invoked.
38 add(*ptr++);
77
78 // process full blocks
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
3 for (; n >= sizeof(m_buf); n -= sizeof(m_buf)) {
80
0/1
✗ Call 0 not invoked.
m_processBlock(ptr);
81 ptr += sizeof(m_buf);
82 m_countBits += sizeof(m_buf) * 8;
83 }
84
85 // process remaining part of block
86
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 3 times.
7 for (; n; n--) {
87
1/1
✓ Call 0 invoked.
4 add(*ptr++);
88 }
89
90 3 return *this;
91 }
92
93 2 sha1 &add(const char *text) {
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
2 if (!text) {
95 return *this;
96 }
97
1/1
✓ Call 0 invoked.
2 return add(text, static_cast<uint32_t>(strlen(text)));
98 }
99
100 1 sha1 &finalize() {
101 // hashed text ends with 0x80, some padding 0x00 and the length in bits
102
1/1
✓ Call 0 invoked.
1 m_addByteDontCountBits(0x80);
103
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 1 times.
13 while (m_index % 64 != 56) {
104
1/1
✓ Call 0 invoked.
12 m_addByteDontCountBits(0x00);
105 }
106
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 1 times.
9 for (int32_t j = 7; j >= 0; j--) {
107
1/1
✓ Call 0 invoked.
8 m_addByteDontCountBits(static_cast<uint8_t>(m_countBits >> j * 8));
108 }
109
110 1 return *this;
111 }
112
113 1 const sha1 &printHex(char *hex, bool zero_terminate = true, const char *alphabet = "0123456789abcdef") const {
114 // print hex
115 1 int k = 0;
116
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1 times.
6 for (int m_index = 0; m_index < 5; m_index++) {
117
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 5 times.
2/2
✓ Decision 'true' taken 40 times.
✓ Decision 'false' taken 5 times.
45 for (int j = 7; j >= 0; j--) {
118
1/1
✓ Call 0 invoked.
40 hex[k++] = alphabet[(m_state[m_index] >> j * 4) & 0xf];
119 }
120 }
121
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (zero_terminate) {
122 1 hex[k] = '\0';
123 }
124 1 return *this;
125 }
126
127 1 const sha1 &printBase64(char *base64, bool zero_terminate = true) const {
128 static const uint8_t *table = (const uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
129 "abcdefghijklmnopqrstuvwxyz"
130 "0123456789"
131 "+/";
132
133 uint32_t triples[7] = {
134
1/1
✓ Call 0 invoked.
1 ((m_state[0] & 0xffffff00) >> 1 * 8),
135
1/1
✓ Call 0 invoked.
1 ((m_state[0] & 0x000000ff) << 2 * 8) | ((m_state[1] & 0xffff0000) >> 2 * 8),
136
1/1
✓ Call 0 invoked.
1 ((m_state[1] & 0x0000ffff) << 1 * 8) | ((m_state[2] & 0xff000000) >> 3 * 8),
137 2 ((m_state[2] & 0x00ffffff) << 0 * 8),
138 2 ((m_state[3] & 0xffffff00) >> 1 * 8),
139
1/1
✓ Call 0 invoked.
1 ((m_state[3] & 0x000000ff) << 2 * 8) | ((m_state[4] & 0xffff0000) >> 2 * 8),
140 2 ((m_state[4] & 0x0000ffff) << 1 * 8),
141
6/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
4 };
142
143
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 1 times.
8 for (int m_index = 0; m_index < 7; m_index++) {
144 7 uint32_t x = triples[m_index];
145 7 base64[m_index * 4 + 0] = table[(x >> 3 * 6) % 64];
146 7 base64[m_index * 4 + 1] = table[(x >> 2 * 6) % 64];
147 7 base64[m_index * 4 + 2] = table[(x >> 1 * 6) % 64];
148 7 base64[m_index * 4 + 3] = table[(x >> 0 * 6) % 64];
149 }
150
151 1 base64[SHA1_BASE64_SIZE - 2] = '=';
152
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (zero_terminate) {
153 1 base64[SHA1_BASE64_SIZE - 1] = '\0';
154 }
155 1 return *this;
156 }
157
158 private:
159 64 void m_addByteDontCountBits(uint8_t x) {
160
1/1
✓ Call 0 invoked.
64 m_buf[m_index++] = x;
161
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 63 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 63 times.
64 if (m_index >= sizeof(m_buf)) {
162 1 m_index = 0;
163
1/1
✓ Call 0 invoked.
2 m_processBlock(m_buf.data());
164 }
165 64 }
166
167 224 static uint32_t m_rol32(uint32_t x, uint32_t n) { return (x << n) | (x >> (32 - n)); }
168
169 16 static uint32_t m_makeWord(const uint8_t *p) { return ((uint32_t)p[0] << 3 * 8) | ((uint32_t)p[1] << 2 * 8) | ((uint32_t)p[2] << 1 * 8) | ((uint32_t)p[3] << 0 * 8); }
170
171 1 void m_processBlock(const uint8_t *ptr) {
172 1 const uint32_t c0 = 0x5a827999;
173 1 const uint32_t c1 = 0x6ed9eba1;
174 1 const uint32_t c2 = 0x8f1bbcdc;
175 1 const uint32_t c3 = 0xca62c1d6;
176
177
1/1
✓ Call 0 invoked.
1 uint32_t a = m_state[0];
178
1/1
✓ Call 0 invoked.
1 uint32_t b = m_state[1];
179
1/1
✓ Call 0 invoked.
1 uint32_t c = m_state[2];
180
1/1
✓ Call 0 invoked.
1 uint32_t d = m_state[3];
181
1/1
✓ Call 0 invoked.
1 uint32_t e = m_state[4];
182
183 uint32_t w[16];
184
185
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 1 times.
17 for (int m_index = 0; m_index < 16; m_index++) {
186
1/1
✓ Call 0 invoked.
16 w[m_index] = m_makeWord(ptr + m_index * 4);
187 }
188
189 #define SHA1_LOAD(m_index) w[m_index & 15] = m_rol32(w[(m_index + 13) & 15] ^ w[(m_index + 8) & 15] ^ w[(m_index + 2) & 15] ^ w[m_index & 15], 1);
190 #define SHA1_ROUND_0(v, u, x, y, z, m_index) \
191 z += ((u & (x ^ y)) ^ y) + w[m_index & 15] + c0 + m_rol32(v, 5); \
192 u = m_rol32(u, 30);
193 #define SHA1_ROUND_1(v, u, x, y, z, m_index) \
194 SHA1_LOAD(m_index) z += ((u & (x ^ y)) ^ y) + w[m_index & 15] + c0 + m_rol32(v, 5); \
195 u = m_rol32(u, 30);
196 #define SHA1_ROUND_2(v, u, x, y, z, m_index) \
197 SHA1_LOAD(m_index) z += (u ^ x ^ y) + w[m_index & 15] + c1 + m_rol32(v, 5); \
198 u = m_rol32(u, 30);
199 #define SHA1_ROUND_3(v, u, x, y, z, m_index) \
200 SHA1_LOAD(m_index) z += (((u | x) & y) | (u & x)) + w[m_index & 15] + c2 + m_rol32(v, 5); \
201 u = m_rol32(u, 30);
202 #define SHA1_ROUND_4(v, u, x, y, z, m_index) \
203 SHA1_LOAD(m_index) z += (u ^ x ^ y) + w[m_index & 15] + c3 + m_rol32(v, 5); \
204 u = m_rol32(u, 30);
205
206
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(a, b, c, d, e, 0);
207
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(e, a, b, c, d, 1);
208
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(d, e, a, b, c, 2);
209
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(c, d, e, a, b, 3);
210
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(b, c, d, e, a, 4);
211
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(a, b, c, d, e, 5);
212
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(e, a, b, c, d, 6);
213
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(d, e, a, b, c, 7);
214
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(c, d, e, a, b, 8);
215
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(b, c, d, e, a, 9);
216
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(a, b, c, d, e, 10);
217
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(e, a, b, c, d, 11);
218
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(d, e, a, b, c, 12);
219
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(c, d, e, a, b, 13);
220
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(b, c, d, e, a, 14);
221
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 SHA1_ROUND_0(a, b, c, d, e, 15);
222
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_1(e, a, b, c, d, 16);
223
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_1(d, e, a, b, c, 17);
224
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_1(c, d, e, a, b, 18);
225
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_1(b, c, d, e, a, 19);
226
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(a, b, c, d, e, 20);
227
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(e, a, b, c, d, 21);
228
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(d, e, a, b, c, 22);
229
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(c, d, e, a, b, 23);
230
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(b, c, d, e, a, 24);
231
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(a, b, c, d, e, 25);
232
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(e, a, b, c, d, 26);
233
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(d, e, a, b, c, 27);
234
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(c, d, e, a, b, 28);
235
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(b, c, d, e, a, 29);
236
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(a, b, c, d, e, 30);
237
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(e, a, b, c, d, 31);
238
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(d, e, a, b, c, 32);
239
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(c, d, e, a, b, 33);
240
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(b, c, d, e, a, 34);
241
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(a, b, c, d, e, 35);
242
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(e, a, b, c, d, 36);
243
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(d, e, a, b, c, 37);
244
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(c, d, e, a, b, 38);
245
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_2(b, c, d, e, a, 39);
246
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(a, b, c, d, e, 40);
247
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(e, a, b, c, d, 41);
248
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(d, e, a, b, c, 42);
249
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(c, d, e, a, b, 43);
250
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(b, c, d, e, a, 44);
251
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(a, b, c, d, e, 45);
252
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(e, a, b, c, d, 46);
253
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(d, e, a, b, c, 47);
254
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(c, d, e, a, b, 48);
255
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(b, c, d, e, a, 49);
256
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(a, b, c, d, e, 50);
257
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(e, a, b, c, d, 51);
258
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(d, e, a, b, c, 52);
259
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(c, d, e, a, b, 53);
260
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(b, c, d, e, a, 54);
261
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(a, b, c, d, e, 55);
262
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(e, a, b, c, d, 56);
263
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(d, e, a, b, c, 57);
264
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(c, d, e, a, b, 58);
265
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_3(b, c, d, e, a, 59);
266
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(a, b, c, d, e, 60);
267
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(e, a, b, c, d, 61);
268
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(d, e, a, b, c, 62);
269
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(c, d, e, a, b, 63);
270
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(b, c, d, e, a, 64);
271
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(a, b, c, d, e, 65);
272
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(e, a, b, c, d, 66);
273
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(d, e, a, b, c, 67);
274
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(c, d, e, a, b, 68);
275
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(b, c, d, e, a, 69);
276
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(a, b, c, d, e, 70);
277
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(e, a, b, c, d, 71);
278
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(d, e, a, b, c, 72);
279
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(c, d, e, a, b, 73);
280
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(b, c, d, e, a, 74);
281
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(a, b, c, d, e, 75);
282
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(e, a, b, c, d, 76);
283
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(d, e, a, b, c, 77);
284
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(c, d, e, a, b, 78);
285
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 SHA1_ROUND_4(b, c, d, e, a, 79);
286
287 #undef SHA1_LOAD
288 #undef SHA1_ROUND_0
289 #undef SHA1_ROUND_1
290 #undef SHA1_ROUND_2
291 #undef SHA1_ROUND_3
292 #undef SHA1_ROUND_4
293
294
1/1
✓ Call 0 invoked.
1 m_state[0] += a;
295
1/1
✓ Call 0 invoked.
1 m_state[1] += b;
296
1/1
✓ Call 0 invoked.
1 m_state[2] += c;
297
1/1
✓ Call 0 invoked.
1 m_state[3] += d;
298
1/1
✓ Call 0 invoked.
1 m_state[4] += e;
299 1 }
300 };
301
302 } // namespace ez
303

Directory: include/ezlibs/
File: ezGraph.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 182 185 98.4%
Functions: 51 51 100.0%
Branches: 62 82 75.6%
Decisions: 33 48 68.8%
Calls: 229 252 90.9%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezGraph is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <set>
30 #include <type_traits>
31 #include <vector>
32 #include <string>
33 #include <memory>
34 #include <cassert>
35 #include <functional>
36
37 namespace ez {
38
39 /////////////////////////////////////
40 ///// Utils /////////////////////////
41 /////////////////////////////////////
42
43 namespace Utils {
44 // if the shared_ptr exit in the container return the iterator
45 template <typename T>
46 typename std::vector<std::shared_ptr<T>>::iterator //
47 22 isSharedPtrExistInVector(const std::shared_ptr<T> &vPtr, std::vector<std::shared_ptr<T>> &vContainer) {
48
1/1
✓ Call 0 invoked.
22 auto ret = vContainer.end();
49
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 11 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
22 if (vPtr != nullptr) {
50
1/1
✓ Call 0 invoked.
22 ret = vContainer.begin();
51
2/2
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 5 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 5 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
24 for (; ret != vContainer.end(); ++ret) {
52
2/2
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
14 if (*ret == vPtr) {
53 12 break;
54 }
55 }
56 }
57 22 return ret;
58 }
59
60 // if the weak_ptr exit in the container return the iterator
61 template <typename T>
62 typename std::vector<std::weak_ptr<T>>::iterator //
63 14 isWeakPtrExistInVector(const std::weak_ptr<T> &vWeak, std::vector<std::weak_ptr<T>> &vContainer) {
64
1/1
✓ Call 0 invoked.
14 auto ret = vContainer.end();
65
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 7 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
14 if (!vWeak.expired()) {
66
1/1
✓ Call 0 invoked.
14 auto ptr = vWeak.lock();
67
1/1
✓ Call 0 invoked.
14 ret = vContainer.begin();
68
2/2
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 1 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 1 times.
2/3
✗ Call 0 not invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
14 for (; ret != vContainer.end(); ++ret) {
69
1/2
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
1/2
✓ Decision 'true' taken 6 times.
✗ Decision 'false' not taken.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
12 if (ret->lock() == ptr) {
70 12 break;
71 }
72 }
73
1/1
✓ Call 0 invoked.
14 }
74 14 return ret;
75 }
76 } // namespace Utils
77
78 /////////////////////////////////////
79 ///// DEFS //////////////////////////
80 /////////////////////////////////////
81
82 enum class SlotDir { INPUT = 0, OUTPUT, Count };
83 enum class RetCodes {
84 SUCCESS = 0,
85 FAILED,
86 FAILED_GRAPH_PTR_NULL,
87 FAILED_SLOT_PTR_NULL,
88 FAILED_SLOT_ALREADY_EXIST,
89 FAILED_SLOT_NOT_FOUND,
90 FAILED_NODE_PTR_NULL,
91 FAILED_NODE_ALREADY_EXIST,
92 FAILED_NODE_NOT_FOUND,
93 Count
94 };
95
96 class Slot;
97 typedef std::shared_ptr<Slot> SlotPtr;
98 typedef std::weak_ptr<Slot> SlotWeak;
99
100 class Node;
101 typedef std::shared_ptr<Node> NodePtr;
102 typedef std::weak_ptr<Node> NodeWeak;
103
104 class Graph;
105 typedef std::shared_ptr<Graph> GraphPtr;
106 typedef std::weak_ptr<Graph> GraphWeak;
107
108 typedef uintptr_t Uuid;
109
110 typedef void *UserDatas;
111
112 /////////////////////////////////////
113 ///// UUID //////////////////////////
114 /////////////////////////////////////
115
116 class UUID {
117 Uuid m_Uuid = 0U;
118
119 public:
120 9 explicit UUID(void *vPtr) { m_Uuid = reinterpret_cast<Uuid>(vPtr); }
121
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
18 virtual ~UUID() = default;
122 template <typename T = Uuid>
123 8 T getUuid() const {
124 8 return static_cast<T>(m_Uuid);
125 }
126 8 virtual void setUuid(const Uuid vUUID) {
127 8 m_Uuid = vUUID;
128 8 }
129 };
130
131 /////////////////////////////////////
132 ///// SLOT //////////////////////////
133 /////////////////////////////////////
134
135 struct SlotDatas {
136 std::string name;
137 std::string type;
138 UserDatas userDatas = nullptr;
139 SlotDir dir = SlotDir::INPUT;
140
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 SlotDatas() = default;
141 SlotDatas(const std::string &vName, const std::string &vType, const SlotDir vSlotDir, UserDatas vUserDatas = nullptr)
142 : name(std::move(vName)), type(std::move(vType)), userDatas(vUserDatas), dir(vSlotDir) {}
143 };
144
145 struct EvalDatas {
146 size_t frame = 0U;
147 };
148
149 class Slot : public UUID {
150 friend class Node;
151 friend class Graph;
152
153 protected:
154 SlotWeak m_This;
155 NodeWeak m_ParentNode;
156 std::shared_ptr<SlotDatas> mp_SlotDatas;
157 std::vector<SlotWeak> m_ConnectedSlots;
158 EvalDatas m_LastEvaluatedDatas;
159
160 public:
161 Slot() : UUID(this) {}
162 template <typename T = SlotDatas>
163
1/1
✓ Branch 4 taken 5 times.
6/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
5 explicit Slot(const T &vDatas) : UUID(this), mp_SlotDatas(std::make_shared<T>(vDatas)) {
164 static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
165
0/3
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
5 }
166
6/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
10 ~Slot() override { unit(); }
167
168 5 virtual bool init() {
169 //assert(!m_This.expired() && "m_This msut be defined with m_setThis during the creation");
170 5 return true;
171 }
172 8 virtual void unit() {
173 // we must rsdet slots
174
1/1
✓ Call 0 invoked.
8 m_ConnectedSlots.clear();
175 // befaore datas
176
1/1
✓ Call 0 invoked.
8 mp_SlotDatas.reset();
177 8 }
178
179 template <typename T = SlotDatas>
180 5 const T &getDatas() const {
181 // remove the need to use a slow dynamic_cast
182 static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
183
1/1
✓ Call 0 invoked.
5 return static_cast<const T &>(*mp_SlotDatas);
184 }
185
186 template <typename T = SlotDatas>
187 T &getDatasRef() {
188 // remove the need to use a slow dynamic_cast
189 static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
190 return static_cast<T &>(*mp_SlotDatas);
191 }
192
193
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
5 void setParentNode(NodeWeak vNodeWeak) { m_ParentNode = std::move(vNodeWeak); }
194 template <typename T = Node>
195 3 std::weak_ptr<T> getParentNode() {
196 // remove the need to use a slow dynamic_cast
197 static_assert(std::is_base_of<Node, T>::value, "T must derive of ez::Node");
198
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
3 return std::static_pointer_cast<T>(m_ParentNode.lock());
199 }
200 2 const std::vector<SlotWeak> &m_getConnectedSlots() { return m_ConnectedSlots; }
201 1 void setLastEvaluatedDatas(const EvalDatas vUserDatas) { m_LastEvaluatedDatas = vUserDatas; }
202 1 const EvalDatas &getLastEvaluatedDatas() const { return m_LastEvaluatedDatas; }
203
204 protected:
205 template <typename T = Slot>
206 std::weak_ptr<T> m_getThis() {
207 static_assert(std::is_base_of<Slot, T>::value, "T must derive of ez::Slot");
208 assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
209 return std::static_pointer_cast<T>(m_This.lock());
210 }
211
1/1
✓ Call 0 invoked.
5 void m_setThis(const SlotWeak &vThis) { m_This = vThis; }
212
213 template <typename T = SlotDatas>
214 explicit Slot(std::shared_ptr<T> vpDatas) : UUID(this), mp_SlotDatas(std::move(vpDatas)) {
215 static_assert(std::is_base_of<SlotDatas, T>::value, "T must derive of ez::SlotDatas");
216 }
217
218 4 RetCodes m_connectSlot(const SlotWeak &vSlot) {
219 4 auto ret = RetCodes::FAILED_SLOT_PTR_NULL;
220
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (!vSlot.expired()) {
221
1/1
✓ Call 0 invoked.
4 m_ConnectedSlots.push_back(vSlot);
222 4 ret = RetCodes::SUCCESS;
223 }
224 4 return ret;
225 }
226
227 RetCodes m_disconnectSlot(const SlotWeak &vSlot) {
228 auto ret = RetCodes::FAILED_SLOT_ALREADY_EXIST;
229 const auto it = Utils::isWeakPtrExistInVector(vSlot, m_ConnectedSlots);
230 if (it != m_ConnectedSlots.end()) {
231 m_ConnectedSlots.erase(it);
232 ret = RetCodes::SUCCESS;
233 }
234 return ret;
235 }
236
237 void m_disconnect() { m_ConnectedSlots.clear(); }
238 };
239
240 /////////////////////////////////////
241 ///// NODE //////////////////////////
242 /////////////////////////////////////
243
244 struct NodeDatas {
245 std::string name;
246 std::string type;
247 UserDatas userDatas = nullptr;
248 NodeDatas() = default;
249 3 NodeDatas(const std::string &vName, const std::string &vType, UserDatas vUserDatas = nullptr)
250
1/1
✓ Branch 4 taken 3 times.
4/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✗ Call 6 not invoked.
3 : name(std::move(vName)), type(std::move(vType)), userDatas(vUserDatas) {}
251 };
252
253 class Node : public UUID {
254 friend class Graph;
255 NodeWeak m_This;
256 GraphWeak m_ParentGraph;
257 bool dirty = false;
258 std::shared_ptr<NodeDatas> mp_NodeDatas;
259 std::vector<SlotPtr> m_Inputs;
260 std::vector<SlotWeak> m_InputWeaks;
261 std::vector<SlotPtr> m_Outputs;
262 std::vector<SlotWeak> m_OutputWeaks;
263
264 public:
265 Node() : UUID(this) {}
266 template <typename T = NodeDatas>
267
1/1
✓ Branch 4 taken 3 times.
10/10
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✓ Call 11 invoked.
3 explicit Node(const T &vDatas) : UUID(this), mp_NodeDatas(std::make_shared<T>(vDatas)) {
268 static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
269
0/3
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
3 }
270
9/9
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
6 ~Node() override { unit(); }
271
272 6 virtual bool init() {
273 //assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
274 6 return true;
275 }
276 6 virtual void unit() {
277 // we must reset slots
278
1/1
✓ Call 0 invoked.
6 m_Inputs.clear();
279
1/1
✓ Call 0 invoked.
6 m_InputWeaks.clear();
280
1/1
✓ Call 0 invoked.
6 m_Outputs.clear();
281
1/1
✓ Call 0 invoked.
6 m_OutputWeaks.clear();
282 // before reset this ans parentGraph
283
1/1
✓ Call 0 invoked.
6 m_This.reset();
284
1/1
✓ Call 0 invoked.
6 m_ParentGraph.reset();
285
1/1
✓ Call 0 invoked.
6 mp_NodeDatas.reset();
286 6 }
287
288 // Datas
289
1/1
✓ Call 0 invoked.
3 void setParentGraph(const GraphWeak &vParentGraph) { m_ParentGraph = vParentGraph; }
290 template <typename T = Graph>
291 std::weak_ptr<T> getParentGraph() {
292 // remove the need to use a slow dynamic_cast
293 static_assert(std::is_base_of<Graph, T>::value, "T must derive of ez::Graph");
294 return std::static_pointer_cast<T>(m_ParentGraph.lock());
295 }
296
297 template <typename T = NodeDatas>
298 24 const T &getDatas() const {
299 // remove the need to use a slow dynamic_cast
300 static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
301
1/1
✓ Call 0 invoked.
24 return static_cast<const T &>(*mp_NodeDatas);
302 }
303
304 template <typename T = NodeDatas>
305 3 T &getDatasRef() {
306 // remove the need to use a slow dynamic_cast
307 static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
308
1/1
✓ Call 0 invoked.
3 return static_cast<T &>(*mp_NodeDatas);
309 }
310 void setDirty(const bool vFlag) { dirty = vFlag; }
311 bool isDirty() const { return dirty; }
312
313 protected: // Node
314 template <typename T = Node>
315 5 std::weak_ptr<T> m_getThis() {
316 static_assert(std::is_base_of<Node, T>::value, "T must derive of ez::Node");
317
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
5 assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
318
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
5 return std::static_pointer_cast<T>(m_This.lock());
319 }
320
1/1
✓ Call 0 invoked.
6 void m_setThis(const NodeWeak &vThis) { m_This = vThis; }
321
322 void m_setSlotThis(SlotPtr vSlotPtr) {
323 if (vSlotPtr != nullptr) {
324 vSlotPtr->m_setThis(vSlotPtr);
325 }
326 }
327
328 template <typename T = NodeDatas>
329 explicit Node(std::shared_ptr<T> vpDatas) : UUID(this), mp_NodeDatas(std::move(vpDatas)) {
330 static_assert(std::is_base_of<NodeDatas, T>::value, "T must derive of ez::NodeDatas");
331 }
332
333 // Slots
334 10 RetCodes m_addSlot(const SlotPtr &vSlotPtr) {
335 10 auto ret = RetCodes::FAILED;
336
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 5 times.
1/1
✓ Call 0 invoked.
10 if (vSlotPtr != nullptr) {
337
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
5 vSlotPtr->m_setThis(vSlotPtr);
338
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
5 vSlotPtr->setUuid(vSlotPtr->getUuid()); // call the virtual setUuid for derived classes
339
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
5 const auto &datas = vSlotPtr->getDatas<SlotDatas>();
340
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 3 times.
5 if (datas.dir == SlotDir::INPUT) {
341
1/1
✓ Call 0 invoked.
2 const auto it = Utils::isSharedPtrExistInVector(vSlotPtr, m_Inputs);
342
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 if (it == m_Inputs.end()) {
343
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
2 vSlotPtr->setParentNode(m_getThis());
344
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 m_Inputs.push_back(vSlotPtr);
345
1/1
✓ Branch 2 taken 2 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
2 m_InputWeaks.push_back(vSlotPtr);
346 2 ret = RetCodes::SUCCESS;
347 } else {
348 ret = RetCodes::FAILED_SLOT_ALREADY_EXIST;
349 }
350
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
3 } else if (datas.dir == SlotDir::OUTPUT) {
351
1/1
✓ Call 0 invoked.
3 const auto it = Utils::isSharedPtrExistInVector(vSlotPtr, m_Outputs);
352
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 if (it == m_Outputs.end()) {
353
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
3 vSlotPtr->setParentNode(m_getThis());
354
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 m_Outputs.push_back(vSlotPtr);
355
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_OutputWeaks.push_back(vSlotPtr);
356 3 ret = RetCodes::SUCCESS;
357 } else {
358 ret = RetCodes::FAILED_SLOT_ALREADY_EXIST;
359 }
360 }
361 }
362 10 return ret;
363 }
364
365 template <typename T = Slot>
366 std::shared_ptr<T> m_addSlot(const SlotDatas &vSlotDatas, RetCodes *vOutRetCodes) {
367 static_assert(std::is_base_of<Slot, T>::value, "T must derive of ez::Slot");
368 if (vOutRetCodes != nullptr) {
369 *vOutRetCodes = RetCodes::FAILED_NODE_PTR_NULL;
370 }
371 auto slot_ptr = std::make_shared<T>(vSlotDatas);
372 const auto ret_code = m_addSlot(slot_ptr);
373 if (vOutRetCodes != nullptr) {
374 *vOutRetCodes = ret_code;
375 }
376 return slot_ptr;
377 }
378
379 3 RetCodes m_delSlot(const SlotWeak &vSlot) {
380
1/1
✓ Call 0 invoked.
3 auto ret = m_delInputSlot(vSlot);
381
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
3 if (ret != RetCodes::SUCCESS) {
382
1/1
✓ Call 0 invoked.
1 ret = m_delOutputSlot(vSlot);
383 }
384 3 return ret;
385 }
386
387 3 RetCodes m_delInputSlot(const SlotWeak &vSlot) {
388 3 auto ret = RetCodes::FAILED_SLOT_NOT_FOUND;
389 // we must detroy the weak before the related shared ptr
390
1/1
✓ Call 0 invoked.
3 auto itWeak = Utils::isWeakPtrExistInVector(vSlot, m_InputWeaks);
391
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 if (itWeak != m_InputWeaks.end()) {
392
1/1
✓ Branch 2 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 m_InputWeaks.erase(itWeak);
393 // so next, the shared ptr
394
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
2 auto itShared = Utils::isSharedPtrExistInVector(vSlot.lock(), m_Inputs);
395
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 if (itShared != m_Inputs.end()) {
396
1/1
✓ Branch 3 taken 2 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
2 itShared->get()->unit();
397
1/1
✓ Branch 2 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 m_Inputs.erase(itShared);
398 2 ret = RetCodes::SUCCESS;
399 }
400 }
401 3 return ret;
402 }
403
404 1 RetCodes m_delOutputSlot(const SlotWeak &vSlot) {
405 1 auto ret = RetCodes::FAILED_SLOT_NOT_FOUND;
406 // we must detroy the weak before the related shared ptr
407
1/1
✓ Call 0 invoked.
1 auto itWeak = Utils::isWeakPtrExistInVector(vSlot, m_OutputWeaks);
408
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 if (itWeak != m_OutputWeaks.end()) {
409
1/1
✓ Branch 2 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 m_OutputWeaks.erase(itWeak);
410 // so next, the shared ptr
411
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 const auto itShared = Utils::isSharedPtrExistInVector(vSlot.lock(), m_Outputs);
412
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 if (itShared != m_Outputs.end()) {
413
1/1
✓ Branch 3 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 itShared->get()->unit();
414
1/1
✓ Branch 2 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 m_Outputs.erase(itShared);
415 1 ret = RetCodes::SUCCESS;
416 }
417 }
418 1 return ret;
419 }
420
421 const std::vector<SlotWeak> &m_getInputSlots() { return m_InputWeaks; }
422 1 std::vector<SlotWeak> &m_getInputSlotsRef() { return m_InputWeaks; }
423
424 const std::vector<SlotWeak> &m_getOutputSlots() { return m_OutputWeaks; }
425 std::vector<SlotWeak> &m_getOutputSlotsRef() { return m_OutputWeaks; }
426 };
427
428 /////////////////////////////////////
429 ///// GRAPH /////////////////////////
430 /////////////////////////////////////
431
432 struct GraphDatas {
433 std::string name;
434 std::string type;
435 UserDatas userDatas = nullptr;
436 GraphDatas() = default;
437 1 GraphDatas(const std::string &vName, const std::string &vType, UserDatas vUserDatas = nullptr)
438
1/1
✓ Branch 4 taken 1 times.
4/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✗ Call 6 not invoked.
1 : name(std::move(vName)), type(std::move(vType)), userDatas(vUserDatas) {}
439 };
440
441 class Graph : public UUID {
442 GraphWeak m_This;
443 NodeWeak m_ParentNode;
444 bool dirty = false;
445 std::shared_ptr<GraphDatas> mp_GraphDatas;
446 std::vector<NodePtr> m_Nodes;
447 std::vector<NodeWeak> m_NodeWeaks;
448
449 public:
450 Graph() : UUID(this) {}
451 template <typename T = GraphDatas>
452
1/1
✓ Branch 4 taken 1 times.
8/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
1 explicit Graph(const T &vDatas) : UUID(this), mp_GraphDatas(std::make_shared<T>(vDatas)) {
453 static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
454
0/3
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
1 }
455
7/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
2 ~Graph() override { unit(); }
456
457 1 virtual bool init() {
458 //assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
459 1 return true;
460 }
461 1 virtual void unit() {
462
1/1
✓ Call 0 invoked.
1 m_This.reset();
463
1/1
✓ Call 0 invoked.
1 m_ParentNode.reset();
464
1/1
✓ Call 0 invoked.
1 mp_GraphDatas.reset();
465
1/1
✓ Call 0 invoked.
1 clear();
466 1 }
467
468 1 virtual void clear() {
469
1/1
✓ Call 0 invoked.
1 m_Nodes.clear();
470
1/1
✓ Call 0 invoked.
1 m_NodeWeaks.clear();
471 1 }
472
473 // Datas
474 void setParentNode(const NodeWeak &vParentNode) { m_ParentNode = vParentNode; }
475 template <typename T = Node>
476 std::weak_ptr<T> getParentNode() {
477 // remove the need to use a slow dynamic_cast
478 static_assert(std::is_base_of<Node, T>::value, "T must derive of ez::Node");
479 return std::static_pointer_cast<T>(m_ParentNode.lock());
480 }
481
482 template <typename T = GraphDatas>
483 8 const T &getDatas() const {
484 // remove the need to use a slow dynamic_cast
485 static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
486
1/1
✓ Call 0 invoked.
8 return static_cast<const T &>(*mp_GraphDatas);
487 }
488
489 template <typename T = GraphDatas>
490 1 T &getDatasRef() {
491 // remove the need to use a slow dynamic_cast
492 static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
493
1/1
✓ Call 0 invoked.
1 return static_cast<T &>(*mp_GraphDatas);
494 }
495
496 const std::vector<NodeWeak> &getNodes() const { return m_NodeWeaks; }
497 std::vector<NodeWeak> &getNodesRef() { return m_NodeWeaks; }
498
499 void setDirty(const bool vFlag) { dirty = vFlag; }
500 bool isDirty() const { return dirty; }
501
502 protected: // Node
503 template <typename T = Graph>
504 3 std::weak_ptr<T> m_getThis() {
505 static_assert(std::is_base_of<Graph, T>::value, "T must derive of ez::Graph");
506
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
3 assert(!m_This.expired() && "m_This msut be defined with m_setThis suring the ceration");
507
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
3 return std::static_pointer_cast<T>(m_This.lock());
508 }
509
1/1
✓ Call 0 invoked.
1 void m_setThis(const GraphWeak &vThis) { m_This = vThis; }
510
511 void m_setNodeThis(NodePtr vNodePtr) {
512 if (vNodePtr != nullptr) {
513 vNodePtr->m_setThis(vNodePtr);
514 }
515 }
516
517 template <typename T = GraphDatas>
518 explicit Graph(std::shared_ptr<T> vpDatas) : UUID(this), mp_GraphDatas(std::move(vpDatas)) {
519 static_assert(std::is_base_of<GraphDatas, T>::value, "T must derive of ez::GraphDatas");
520 }
521
522 6 RetCodes m_addNode(const NodePtr &vNodePtr) {
523 6 auto ret = RetCodes::FAILED_NODE_PTR_NULL;
524
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
6 if (vNodePtr != nullptr) {
525
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
3 vNodePtr->m_setThis(vNodePtr);
526
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
3 vNodePtr->setUuid(vNodePtr->getUuid()); // call the virtual setUuid for derived classes
527
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
3 vNodePtr->setParentGraph(m_getThis());
528
1/1
✓ Call 0 invoked.
3 m_Nodes.push_back(vNodePtr);
529
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_NodeWeaks.push_back(vNodePtr);
530 3 ret = RetCodes::SUCCESS;
531 }
532 6 return ret;
533 }
534
535 3 RetCodes m_delNode(const NodeWeak &vNode) {
536 3 auto ret = RetCodes::FAILED_NODE_NOT_FOUND;
537
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
3 const auto itShared = Utils::isSharedPtrExistInVector(vNode.lock(), m_Nodes);
538
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 if (itShared != m_Nodes.end()) {
539
1/1
✓ Branch 3 taken 3 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
3 itShared->get()->unit();
540
1/1
✓ Branch 2 taken 3 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 m_Nodes.erase(itShared);
541
1/1
✓ Call 0 invoked.
3 auto itWeak = Utils::isWeakPtrExistInVector(vNode, m_NodeWeaks);
542
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 if (itWeak != m_NodeWeaks.end()) {
543
1/1
✓ Branch 2 taken 3 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3 m_NodeWeaks.erase(itWeak);
544 3 ret = RetCodes::SUCCESS;
545 }
546 }
547 3 return ret;
548 }
549
550 4 static RetCodes m_connectSlots(const SlotWeak &vFrom, const SlotWeak &vTo) {
551 4 auto ret = RetCodes::FAILED_SLOT_PTR_NULL;
552
6/6
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
4 if (!vFrom.expired() && !vTo.expired()) {
553
1/1
✓ Call 0 invoked.
2 const auto fromPtr = vFrom.lock();
554
1/1
✓ Call 0 invoked.
2 const auto toPtr = vTo.lock();
555
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
2 if (fromPtr != nullptr && toPtr != nullptr) {
556
1/1
✓ Branch 2 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 ret = fromPtr->m_connectSlot(vTo);
557
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2 if (ret == RetCodes::SUCCESS) {
558
1/1
✓ Branch 2 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 ret = toPtr->m_connectSlot(vFrom);
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
2 if (ret != RetCodes::SUCCESS) {
560
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
fromPtr->m_connectSlot(vTo);
561 }
562 }
563 }
564
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
2 }
565 4 return ret;
566 }
567
568 static RetCodes m_disconnectSlots(const SlotWeak &vFrom, const SlotWeak &vTo) {
569 auto ret = RetCodes::FAILED_SLOT_PTR_NULL;
570 const auto fromPtr = vFrom.lock();
571 const auto toPtr = vTo.lock();
572 if (fromPtr != nullptr) {
573 ret = fromPtr->m_disconnectSlot(vTo);
574 }
575 if (toPtr != nullptr) {
576 ret = toPtr->m_disconnectSlot(vFrom);
577 }
578 return ret;
579 }
580 };
581
582 } // namespace ez
583

Directory: include/ezlibs/
File: ezMath.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 70 70 100.0%
Functions: 79 79 100.0%
Branches: 24 24 100.0%
Decisions: 6 6 100.0%
Calls: 29 30 96.7%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezMath is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <type_traits>
30 #include <cmath>
31 #include <string>
32 #include <sstream>
33 #include <iomanip>
34 #include <cstdint>
35 #include <limits>
36
37 ////////////////////////////////////////////////////////////////////////////
38 ////////////////////////////////////////////////////////////////////////////
39 ////////////////////////////////////////////////////////////////////////////
40
41 #ifdef _MSC_VER
42 #pragma warning(push)
43 #pragma warning(disable : 4244) // Conversion from 'double' to 'float', possible loss of data
44 #pragma warning(disable : 4305) // Truncation from 'double' to 'float'
45 #elif defined(__GNUC__) || defined(__clang__)
46 #pragma GCC diagnostic push
47 #pragma GCC diagnostic ignored "-Wconversion"
48 #pragma GCC diagnostic ignored "-Wfloat-conversion"
49 #endif
50
51 ////////////////////////////////////////////////////////////////////////////
52 ////////////////////////////////////////////////////////////////////////////
53 ////////////////////////////////////////////////////////////////////////////
54
55 namespace ez {
56
57 #ifndef M_PI
58 #define M_PI 3.1415926535897932384626433832795
59 #endif
60
61 #ifndef M_E
62 #define M_E 2.7182818284590452353602874713527
63 #endif
64
65 // This function rounds a floating-point number to 'n' decimal places.
66 // Only floating-point types (float, double, long double) are allowed.
67 template <typename T>
68 24 inline std::string round_n(T vValue, int n) {
69 static_assert(std::is_floating_point<T>::value, "round_n is only valid for floating point types");
70
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
24 std::stringstream tmp;
71
2/2
✓ Branch 3 taken 12 times.
✓ Branch 6 taken 12 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
24 tmp << std::setprecision(n) << std::fixed << vValue;
72
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
48 return tmp.str();
73
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
24 }
74
75 /// This function is used to ensure that a floating point number is not a NaN or infinity.
76 5 inline bool floatIsValid(float x) {
77 const union {
78 float f;
79 int32_t i;
80 5 } v = {x};
81 5 return (v.i & 0x7f800000) != 0x7f800000;
82 }
83
84 // Checks if two numbers are different according to epsilon precision.
85 template <typename T>
86 52 inline bool isDifferent(T vA, T vB) {
87 52 return vA != vB;
88 }
89
90 template <>
91 58 inline bool isDifferent(float vA, float vB) {
92
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
58 return std::fabs(vA - vB) > std::numeric_limits<float>::epsilon();
93 }
94
95 template <>
96 58 inline bool isDifferent(double vA, double vB) {
97
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
58 return std::abs(vA - vB) > std::numeric_limits<double>::epsilon();
98 }
99
100 // Checks if two numbers are equal according to epsilon precision.
101 template <typename T>
102 706 inline bool isEqual(T vA, T vB) {
103
1/1
✓ Call 0 invoked.
706 return vA == vB;
104 }
105
106 template <>
107 110 inline bool isEqual(float vA, float vB) {
108
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
110 return std::fabs(vA - vB) < std::numeric_limits<float>::epsilon();
109 }
110
111 template <>
112 97 inline bool isEqual(double vA, double vB) {
113
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
97 return std::abs(vA - vB) < std::numeric_limits<double>::epsilon();
114 }
115
116 // Rounds a floating-point number to the nearest integer.
117 // Only floating-point types (float, double, long double) are allowed.
118 template <typename T>
119 12 inline T round(T v) {
120 static_assert(std::is_floating_point<T>::value, "round is only valid for floating point types");
121
1/1
✓ Call 0 invoked.
12 return static_cast<T>(std::round(v));
122 }
123
124 // Returns the largest integer less than or equal to the floating-point number.
125 // Only floating-point types (float, double, long double) are allowed.
126 template <typename T>
127 40 inline T floor(T v) {
128 static_assert(std::is_floating_point<T>::value, "floor is only valid for floating point types");
129
1/1
✓ Call 0 invoked.
40 return static_cast<T>(std::floor(v));
130 }
131
132 // Returns the smallest integer greater than or equal to the floating-point number.
133 // Only floating-point types (float, double, long double) are allowed.
134 template <typename T>
135 20 inline T ceil(T v) {
136 static_assert(std::is_floating_point<T>::value, "ceil is only valid for floating point types");
137
1/1
✓ Call 0 invoked.
20 return static_cast<T>(std::ceil(v));
138 }
139
140 // Returns the fractional part of a floating-point number.
141 // Only floating-point types (float, double, long double) are allowed.
142 template <typename T>
143 20 inline T fract(T v) {
144 static_assert(std::is_floating_point<T>::value, "fract is only valid for floating point types");
145
1/1
✓ Call 0 invoked.
20 return v - floor(v);
146 }
147
148 // Computes the cosine of a floating-point number.
149 // Only floating-point types (float, double, long double) are allowed.
150 template <typename T>
151 16 inline T cos(T v) {
152 static_assert(std::is_floating_point<T>::value, "cos is only valid for floating point types");
153
1/1
✓ Call 0 invoked.
16 return std::cos(v);
154 }
155
156 // Computes the arc cosine of a floating-point number.
157 // Only floating-point types (float, double, long double) are allowed.
158 template <typename T>
159 8 inline T acos(T v) {
160 static_assert(std::is_floating_point<T>::value, "acos is only valid for floating point types");
161
1/1
✓ Call 0 invoked.
8 return std::acos(v);
162 }
163
164 // Computes the sine of a floating-point number.
165 // Only floating-point types (float, double, long double) are allowed.
166 template <typename T>
167 16 inline T sin(T v) {
168 static_assert(std::is_floating_point<T>::value, "sin is only valid for floating point types");
169
1/1
✓ Call 0 invoked.
16 return std::sin(v);
170 }
171
172 // Computes the arc sine of a floating-point number.
173 // Only floating-point types (float, double, long double) are allowed.
174 template <typename T>
175 8 inline T asin(T v) {
176 static_assert(std::is_floating_point<T>::value, "asin is only valid for floating point types");
177
1/1
✓ Call 0 invoked.
8 return std::asin(v);
178 }
179
180 // Computes the tangent of a floating-point number.
181 // Only floating-point types (float, double, long double) are allowed.
182 template <typename T>
183 12 inline T tan(T v) {
184 static_assert(std::is_floating_point<T>::value, "tan is only valid for floating point types");
185
1/1
✓ Call 0 invoked.
12 return std::tan(v);
186 }
187
188 // Computes the arc tangent of a floating-point number.
189 // Only floating-point types (float, double, long double) are allowed.
190 template <typename T>
191 16 inline T atan(T v) {
192 static_assert(std::is_floating_point<T>::value, "atan is only valid for floating point types");
193
1/1
✓ Call 0 invoked.
16 return std::atan(v);
194 }
195
196 // Computes the sqrt of a floating-point number.
197 // Only floating-point types (float, double, long double) are allowed.
198 template <typename T>
199 48 inline T sqrt(T v) {
200 static_assert(std::is_floating_point<T>::value, "sqrt is only valid for floating point types");
201
1/1
✓ Call 0 invoked.
48 return std::sqrt(v);
202 }
203
204 // Returns the smaller of two values.
205 // Works with both integral and floating-point types.
206 template <typename T>
207 18259671 inline T mini(T a, T b) {
208
2/2
✓ Branch 0 taken 11263134 times.
✓ Branch 1 taken 2709963 times.
18259671 return a < b ? a : b;
209 }
210
211 // Returns the larger of two values.
212 // Works with both integral and floating-point types.
213 template <typename T>
214 9686631 inline T maxi(T a, T b) {
215
2/2
✓ Branch 0 taken 7767951 times.
✓ Branch 1 taken 1918626 times.
9686631 return a > b ? a : b;
216 }
217
218 // Clamps a value between 0 and 1.
219 // Works with both integral and floating-point types.
220 template <typename T>
221 inline T clamp(T n) {
222 return n >= static_cast<T>(0) && n <= static_cast<T>(1) ? n : static_cast<T>(n > static_cast<T>(0));
223 }
224
225 // Clamps a value between 0 and b.
226 // Works with both integral and floating-point types.
227 template <typename T>
228 inline T clamp(T n, T b) {
229 return n >= static_cast<T>(0) && n <= b ? n : static_cast<T>(n > static_cast<T>(0)) * b;
230 }
231
232 // Clamps a value between a and b.
233 // Works with both integral and floating-point types.
234 template <typename T>
235 37 inline T clamp(T n, T a, T b) {
236
6/6
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
37 return n >= a && n <= b ? n : n < a ? a : b;
237 }
238
239 // Computes the absolute value of a number.
240 // Works with both integral and floating-point types.
241 template <typename T>
242 74 inline T abs(T a) {
243 static_assert(std::is_arithmetic<T>::value, "abs is only valid for arithmetic types");
244
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 11 times.
74 return (a < 0) ? a * static_cast<T>(-1) : a;
245 }
246
247 // Determines the sign of a number (-1 for negative, 1 for positive).
248 // Works with both integral and floating-point types.
249 template <typename T>
250 48 inline T sign(T a) {
251 static_assert(std::is_signed<T>::value, "sign is only valid for signed types");
252
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 20 times.
48 if (a < 0) {
253 8 return static_cast<T>(-1);
254
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 8 times.
40 } else if (a > 0) {
255 24 return static_cast<T>(1);
256 }
257 16 return static_cast<T>(0);
258 }
259
260 // Returns 0 if b < a, otherwise returns 1.
261 // Works with both integral and floating-point types.
262 template <typename T>
263 8 inline T step(T a, T b) {
264 static_assert(std::is_arithmetic<T>::value, "step is only valid for arithmetic types");
265
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
8 return (b < a) ? static_cast<T>(0) : static_cast<T>(1);
266 }
267
268 // Computes the floating-point remainder of the division operation.
269 // Only floating-point types (float, double, long double) are allowed.
270 template <typename T>
271 8 inline T mod(T v, T l) {
272 static_assert(std::is_floating_point<T>::value, "mod is only valid for floating point types");
273
1/1
✓ Call 0 invoked.
8 return std::fmod(v, l);
274 }
275
276 // Computes the inverse of the linear interpolation mix.
277 // Only floating-point types (float, double, long double) are allowed.
278 template <typename T>
279 4 inline T invMix(T i, T s, T r) {
280 static_assert(std::is_floating_point<T>::value, "invMix is only valid for floating point types");
281 4 return (r - i) / (s - i);
282 }
283
284 // Linearly interpolates between a and b by t.
285 // Only floating-point types (float, double, long double) are allowed.
286 template <typename T>
287 16 inline T lerp(T a, T b, T t) {
288 static_assert(std::is_floating_point<T>::value, "lerp is only valid for floating point types");
289 16 return a * (static_cast<T>(1.0) - t) + b * t;
290 }
291
292 // Exponentially interpolates between a and b by t.
293 // Only floating-point types (float, double, long double) are allowed.
294 template <typename T>
295 8 inline T eerp(T a, T b, T t) {
296 static_assert(std::is_floating_point<T>::value, "eerp is only valid for floating point types");
297
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
8 if (a == static_cast<T>(0))
298 4 return static_cast<T>(0);
299
1/1
✓ Call 0 invoked.
4 return std::pow(a * (b / a), t);
300 }
301
302 // Performs linear interpolation (lerp) between a and b by t.
303 // Only floating-point types (float, double, long double) are allowed.
304 template <typename T>
305 4 inline T mix(T a, T b, T t) {
306 static_assert(std::is_floating_point<T>::value, "mix is only valid for floating point types");
307 4 return lerp(a, b, t);
308 }
309
310 } // namespace ez
311
312 #include "ezStr.hpp"
313 #include "ezVec2.hpp"
314 #include "ezVec3.hpp"
315 #include "ezVec4.hpp"
316 #include "ezAABB.hpp"
317 #include "ezQuat.hpp"
318 #include "ezPlane.hpp"
319 #include "ezAABBCC.hpp"
320
321 ////////////////////////////////////////////////////////////////////////////
322 ////////////////////////////////////////////////////////////////////////////
323 ////////////////////////////////////////////////////////////////////////////
324
325 #ifdef _MSC_VER
326 #pragma warning(pop)
327 #elif defined(__GNUC__) || defined(__clang__)
328 #pragma GCC diagnostic pop
329 #endif
330
331 ////////////////////////////////////////////////////////////////////////////
332 ////////////////////////////////////////////////////////////////////////////
333 ////////////////////////////////////////////////////////////////////////////
334

Directory: include/ezlibs/
File: ezVec2.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 72 73 98.6%
Functions: 160 160 100.0%
Branches: 12 15 80.0%
Decisions: 1 2 50.0%
Calls: 49 49 100.0%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 #ifndef EZ_TOOLS_VEC2
4 #define EZ_TOOLS_VEC2
5 #endif // EZ_TOOLS_VEC2
6
7 /*
8 MIT License
9
10 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 */
30
31 // ezVec2 is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
32
33 #include <cmath>
34 #include <type_traits>
35 #include <string>
36 #include <vector>
37
38 #ifdef min
39 #undef min
40 #endif // min
41
42 #ifdef max
43 #undef max
44 #endif // max
45
46 // Namespace ez
47 namespace ez {
48
49 // Disable specific types for template functions
50 template <typename T>
51 struct is_valid_type : std::integral_constant<bool, (std::is_floating_point<T>::value || (std::is_integral<T>::value && sizeof(T) > 1))> {};
52
53 // Vector 2D template class
54 template <typename T>
55 struct vec2 {
56 // Disable this template if T is not an integral or floating point type
57 static_assert(is_valid_type<T>::value, "Invalid type for vec2. Only integral types larger than (u)int16_t and floating-point types are allowed.");
58
59 T x = static_cast<T>(0), y = static_cast<T>(0);
60
61 // Constructors
62 vec2() = default;
63
64 // Constructor with type conversion
65 template <typename U>
66 vec2(const vec2<U>& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)) {}
67
68 // Constructor with type conversion
69 template <typename U>
70 vec2(const U& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)) {}
71
72 vec2(T a) : x(a), y(a) {}
73
74 696 vec2(T a, T b) : x(a), y(b) {}
75
76 #ifdef EZ_STR
77 vec2(const std::vector<std::string>& vArray) {
78 const size_t s = vArray.size();
79 if (s > 0) {
80 str::stringToNumber(vArray.at(0), x);
81 }
82 if (s > 1) {
83 str::stringToNumber(vArray.at(1), y);
84 }
85 };
86
87 vec2(const std::string& vec, char c = ';', const vec2<T>* def = nullptr) {
88 if (def) {
89 x = def->x;
90 y = def->y;
91 }
92 std::vector<T> result = str::stringToNumberVector<T>(vec, c);
93 const size_t s = result.size();
94 if (s > 0) {
95 x = result.at(0);
96 }
97 if (s > 1) {
98 x = result.at(1);
99 }
100 }
101 #endif
102
103 // Element access operator
104 T& operator[](size_t i) { return (&x)[i]; }
105
106 // Offset function
107
1/1
✓ Call 0 invoked.
12 vec2 Offset(T vX, T vY) const { return vec2(x + vX, y + vY); }
108
109 // Set function
110 void Set(T vX, T vY) {
111 x = vX;
112 y = vY;
113 }
114
115 vec2 lerp(const vec2<T>& vPos, T vLerpValue) {
116 static_assert(std::is_floating_point<T>::value, "lerp is only valid for floating point types");
117 return vec2( //
118 ez::lerp(x, vPos.x, vLerpValue),
119 ez::lerp(y, vPos.y, vLerpValue));
120
121 }
122
123 vec2 lerp(const vec2<T>& vPos, const vec2<T>& vLerpValue) {
124 static_assert(std::is_floating_point<T>::value, "lerp is only valid for floating point types");
125 return vec2( //
126 ez::lerp(x, vPos.x, vLerpValue.x),
127 ez::lerp(y, vPos.y, vLerpValue.y));
128 }
129
130 // Negation operator
131 8 vec2 operator-() const {
132 static_assert(std::is_signed<T>::value, "Negation operator is only valid for signed types");
133
1/1
✓ Call 0 invoked.
8 return vec2(-x, -y);
134 }
135
136 // Logical NOT operator
137 vec2 operator!() const {
138 static_assert(std::is_integral<T>::value, "Logical NOT is only valid for integral types");
139 return vec2(!x, !y);
140 }
141
142 // Increment and decrement operators
143 vec2& operator++() {
144 ++x;
145 ++y;
146 return *this;
147 }
148
149 vec2& operator--() {
150 --x;
151 --y;
152 return *this;
153 }
154
155 vec2 operator++(int) {
156 vec2 tmp = *this;
157 ++*this;
158 return tmp;
159 }
160
161 vec2 operator--(int) {
162 vec2 tmp = *this;
163 --*this;
164 return tmp;
165 }
166
167 // Compound assignment operators
168 void operator+=(T a) {
169 x += a;
170 y += a;
171 }
172
173 void operator+=(const vec2<T>& v) {
174 x += v.x;
175 y += v.y;
176 }
177
178 void operator-=(T a) {
179 x -= a;
180 y -= a;
181 }
182
183 void operator-=(const vec2<T>& v) {
184 x -= v.x;
185 y -= v.y;
186 }
187
188 void operator*=(T a) {
189 x *= a;
190 y *= a;
191 }
192
193 void operator*=(const vec2<T>& v) {
194 x *= v.x;
195 y *= v.y;
196 }
197
198 void operator/=(T a) {
199 x /= a;
200 y /= a;
201 }
202
203 void operator/=(const vec2<T>& v) {
204 x /= v.x;
205 y /= v.y;
206 }
207
208 // Comparison operators
209 bool operator==(T a) const { return (x == a) && (y == a); }
210
211 bool operator==(const vec2<T>& v) const { return (x == v.x) && (y == v.y); }
212
213 bool operator!=(T a) const { return (x != a) || (y != a); }
214
215 bool operator!=(const vec2<T>& v) const { return (x != v.x) || (y != v.y); }
216
217 // Length and normalization
218 20 T lengthSquared() const { return x * x + y * y; }
219
220
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
20 T length() const { return static_cast<T>(ez::sqrt(lengthSquared())); }
221
222 8 T normalize() {
223
1/1
✓ Call 0 invoked.
8 T len = length();
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4 times.
8 if (len < static_cast<T>(1e-5))
225 return static_cast<T>(0.0);
226 8 T invLen = static_cast<T>(1.0) / len;
227 8 x *= invLen;
228 8 y *= invLen;
229 8 return len;
230 }
231
232 4 vec2 GetNormalized() const {
233
1/1
✓ Call 0 invoked.
4 vec2 n(x, y);
234
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
4 n.normalize();
235 4 return n;
236 }
237
238 // Sum functions
239 12 T sum() const { return x + y; }
240
241 T sumAbs() const { return ez::abs(x) + ez::abs(y); }
242
243 // Empty checks
244
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
48 bool emptyAND() const { return x == static_cast<T>(0) && y == static_cast<T>(0); }
245
246
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
48 bool emptyOR() const { return x == static_cast<T>(0) || y == static_cast<T>(0); }
247
248 #ifdef EZ_STR
249 // Convert to string
250 std::string string(char c = ';') const { return str::toStr(x) + c + str::toStr(y); }
251 std::vector<std::string> array(char c = ';') const { return {str::toStr(x), str::toStr(y)}; }
252 #endif
253
254 // Ratio functions
255 template <typename U>
256 U ratioXY() const {
257 if (y != static_cast<T>(0))
258 return static_cast<U>(x) / static_cast<U>(y);
259 return static_cast<U>(0);
260 }
261
262 template <typename U>
263 U ratioYX() const {
264 if (x != static_cast<T>(0))
265 return static_cast<U>(y) / static_cast<U>(x);
266 return static_cast<U>(0);
267 }
268
269 // Min and max
270
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 T min() const { return x < y ? x : y; }
271
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 T max() const { return x > y ? x : y; }
273 };
274
275 // Operators
276 template <typename T>
277 12 inline vec2<T> operator+(const vec2<T>& v, T f) {
278
1/1
✓ Call 0 invoked.
12 return vec2<T>(v.x + f, v.y + f);
279 }
280
281 template <typename T>
282 12 inline vec2<T> operator+(T f, const vec2<T>& v) {
283
1/1
✓ Call 0 invoked.
12 return vec2<T>(v.x + f, v.y + f);
284 }
285
286 template <typename T>
287 12 inline vec2<T> operator+(const vec2<T>& v, const vec2<T>& f) {
288
1/1
✓ Call 0 invoked.
12 return vec2<T>(v.x + f.x, v.y + f.y);
289 }
290
291 template <typename T>
292 12 inline vec2<T> operator-(const vec2<T>& v, T f) {
293
1/1
✓ Call 0 invoked.
12 return vec2<T>(v.x - f, v.y - f);
294 }
295
296 template <typename T>
297 12 inline vec2<T> operator-(T f, const vec2<T>& v) {
298
1/1
✓ Call 0 invoked.
12 return vec2<T>(f - v.x, f - v.y);
299 }
300
301 template <typename T>
302 16 inline vec2<T> operator-(const vec2<T>& v, const vec2<T>& f) {
303
1/1
✓ Call 0 invoked.
16 return vec2<T>(v.x - f.x, v.y - f.y);
304 }
305
306 template <typename T>
307 12 inline vec2<T> operator*(const vec2<T>& v, T f) {
308
1/1
✓ Call 0 invoked.
12 return vec2<T>(v.x * f, v.y * f);
309 }
310
311 template <typename T>
312 16 inline vec2<T> operator*(T f, const vec2<T>& v) {
313
1/1
✓ Call 0 invoked.
16 return vec2<T>(v.x * f, v.y * f);
314 }
315
316 template <typename T>
317 12 inline vec2<T> operator*(const vec2<T>& v, const vec2<T>& f) {
318
1/1
✓ Call 0 invoked.
12 return vec2<T>(v.x * f.x, v.y * f.y);
319 }
320
321 template <typename T>
322 8 inline vec2<T> operator/(const vec2<T>& v, T f) {
323
1/1
✓ Call 0 invoked.
8 return vec2<T>(v.x / f, v.y / f);
324 }
325
326 template <typename T>
327 4 inline vec2<T> operator/(T f, const vec2<T>& v) {
328
1/1
✓ Call 0 invoked.
4 return vec2<T>(f / v.x, f / v.y);
329 }
330
331 template <typename T>
332 8 inline vec2<T> operator/(const vec2<T>& v, const vec2<T>& f) {
333
1/1
✓ Call 0 invoked.
8 return vec2<T>(v.x / f.x, v.y / f.y);
334 }
335
336 // Comparison operators
337 template <typename T>
338 inline bool operator<(const vec2<T>& v, const vec2<T>& f) {
339 return v.x < f.x && v.y < f.y;
340 }
341
342 template <typename T>
343 inline bool operator<(const vec2<T>& v, T f) {
344 return v.x < f && v.y < f;
345 }
346
347 template <typename T>
348 inline bool operator>(const vec2<T>& v, const vec2<T>& f) {
349 return v.x > f.x && v.y > f.y;
350 }
351
352 template <typename T>
353 inline bool operator>(const vec2<T>& v, T f) {
354 return v.x > f && v.y > f;
355 }
356
357 template <typename T>
358 inline bool operator<=(const vec2<T>& v, const vec2<T>& f) {
359 return v.x <= f.x && v.y <= f.y;
360 }
361
362 template <typename T>
363 inline bool operator<=(const vec2<T>& v, T f) {
364 return v.x <= f && v.y <= f;
365 }
366
367 template <typename T>
368 inline bool operator>=(const vec2<T>& v, const vec2<T>& f) {
369 return v.x >= f.x && v.y >= f.y;
370 }
371
372 template <typename T>
373 inline bool operator>=(const vec2<T>& v, T f) {
374 return v.x >= f && v.y >= f;
375 }
376
377 template <typename T>
378 inline bool operator!=(const vec2<T>& v, const vec2<T>& f) {
379 return f.x != v.x || f.y != v.y;
380 }
381
382 template <typename T>
383 inline bool operator==(const vec2<T>& v, const vec2<T>& f) {
384 return f.x == v.x && f.y == v.y;
385 }
386
387 // Additional vector operations
388 template <typename T>
389 4 inline vec2<T> floor(const vec2<T>& a) {
390
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 return vec2<T>(ez::floor(a.x), ez::floor(a.y));
391 }
392
393 template <typename T>
394 4 inline vec2<T> fract(const vec2<T>& a) {
395 static_assert(std::is_floating_point<T>::value, "fract is only valid for theses types : float, double, long double");
396
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 return vec2<T>(fract(a.x), fract(a.y));
397 }
398
399 template <typename T>
400 4 inline vec2<T> ceil(const vec2<T>& a) {
401
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 return vec2<T>(ez::ceil(a.x), ez::ceil(a.y));
402 }
403
404 template <typename T>
405 12 inline vec2<T> mini(const vec2<T>& a, const vec2<T>& b) {
406
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
12 return vec2<T>(ez::mini(a.x, b.x), ez::mini(a.y, b.y));
407 }
408
409 template <typename T>
410 12 inline vec2<T> maxi(const vec2<T>& a, const vec2<T>& b) {
411
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
12 return vec2<T>(ez::maxi(a.x, b.x), ez::maxi(a.y, b.y));
412 }
413
414 // scalar prodcut not possible with (u)int8
415 template <typename T>
416 16 inline T dot(const vec2<T>& a, const vec2<T>& b) {
417 16 return a.x * b.x + a.y * b.y;
418 }
419
420 template <typename T>
421 12 inline T det(const vec2<T>& a, const vec2<T>& b) {
422 12 return a.x * b.y - a.y * b.x;
423 }
424
425 template <typename T>
426 inline T length(const vec2<T>& v) {
427 return sqrt(dot(v,v));
428 }
429
430 template <typename T>
431 inline vec2<T> cross(const vec2<T>& a, const vec2<T>& b) {
432 return vec2<T>(a.x * b.y - a.y * b.x, a.y * b.x - a.x * b.y);
433 }
434
435 template <typename T>
436 4 inline vec2<T> reflect(const vec2<T>& I, const vec2<T>& N) {
437 static_assert(std::is_floating_point<T>::value, "fract is only valid for floating point types");
438
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 return I - static_cast<T>(2) * ez::dot(N, I) * N;
439 }
440
441 template <typename T>
442 16 inline vec2<T> sign(const vec2<T>& a) {
443
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
16 return vec2<T>(ez::sign(a.x), ez::sign(a.y));
444 }
445
446 template <typename T>
447 4 inline vec2<T> sin(const vec2<T>& a) {
448
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 return vec2<T>(ez::sin(a.x), ez::sin(a.y));
449 }
450
451 template <typename T>
452 4 inline vec2<T> cos(const vec2<T>& a) {
453
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 return vec2<T>(ez::cos(a.x), ez::cos(a.y));
454 }
455
456 template <typename T>
457 4 inline vec2<T> tan(const vec2<T>& a) {
458
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 return vec2<T>(ez::tan(a.x), ez::tan(a.y));
459 }
460
461 template <typename T>
462 2 inline vec2<T> atan(const vec2<T>& a) {
463 2 return vec2<T>(ez::atan(a.x), ez::atan(a.y));
464 }
465
466 // Clamps a value between 0 and 1.
467 // Works with both integral and floating-point types.
468 template <typename T>
469 inline vec2<T> clamp(vec2<T> n) {
470 vec2<T> ret;
471 ret.x = ez::clamp(n.x);
472 ret.y = ez::clamp(n.y);
473 return ret;
474 }
475
476 // Clamps a value between 0 and b.
477 // Works with both integral and floating-point types.
478 template <typename T>
479 inline vec2<T> clamp(vec2<T> n, T b) {
480 vec2<T> ret;
481 ret.x = ez::clamp(n.x);
482 ret.y = ez::clamp(n.y);
483 return ret;
484 }
485
486 // Clamps a value between a and b.
487 // Works with both integral and floating-point types.
488 template <typename T>
489 inline vec2<T> clamp(vec2<T> n, T a, T b) {
490 vec2<T> ret;
491 ret.x = ez::clamp(n.x, a, b);
492 ret.y = ez::clamp(n.y, a, b);
493 return ret;
494 }
495
496 // Using statements for different types of vec2
497 using dvec2 = vec2<double>;
498 using fvec2 = vec2<float>;
499 using f32vec2 = vec2<float>;
500 using f64vec2 = vec2<double>;
501 using i8vec2 = vec2<int8_t>;
502 using i16vec2 = vec2<int16_t>;
503 using ivec2 = vec2<int32_t>;
504 using i32vec2 = vec2<int32_t>;
505 using i64vec2 = vec2<int64_t>;
506 using u8vec2 = vec2<uint8_t>;
507 using u16vec2 = vec2<uint16_t>;
508 using uvec2 = vec2<uint32_t>;
509 using u32vec2 = vec2<uint32_t>;
510 using u64vec2 = vec2<uint64_t>;
511
512 // Conversion functions
513 inline fvec2 convert(const ivec2& v) {
514 return fvec2(static_cast<float>(v.x), static_cast<float>(v.y));
515 }
516
517 inline ivec2 convert(const fvec2& v) {
518 return ivec2(static_cast<int>(v.x), static_cast<int>(v.y));
519 }
520
521 #ifdef floatIsValid
522 // Float validation
523 inline bool valid(const fvec2& a) {
524 return floatIsValid(a.x) && floatIsValid(a.y);
525 }
526 #endif
527
528 #ifdef isEqual
529 // Float comparison operators
530 inline bool operator==(const fvec2& v, const fvec2& f) {
531 return isEqual(f.x, v.x) && isEqual(f.y, v.y);
532 }
533 #endif
534
535 #ifdef isDifferent
536 inline bool operator!=(const fvec2& v, const fvec2& f) {
537 return isDifferent(f.x, v.x) || isDifferent(f.y, v.y);
538 }
539 #endif
540
541 // Function to compute the angle in radians from a vec2, only for floating-point types
542 // Allowed types: float, double, long double
543 template <typename T>
544 inline typename std::enable_if<std::is_floating_point<T>::value, T>::type radAngleFromVec2(const vec2<T>& vec) {
545 T angle = static_cast<T>(0);
546 if (vec.lengthSquared() > static_cast<T>(0) && vec.x != static_cast<T>(0)) {
547 angle = ez::atan(vec.y / vec.x);
548 }
549 return angle;
550 }
551
552 // Function to compute the continuous angle in radians from a vec2 with an offset, only for floating-point types
553 // Allowed types: float, double, long double
554 template <typename T>
555 inline typename std::enable_if<std::is_floating_point<T>::value, T>::type radAngleContinuousFromVec2(const vec2<T>& vec, T angleOffset) {
556 T angle = static_cast<T>(0);
557 if (vec.x > static_cast<T>(0)) {
558 angle = ez::atan(vec.y / vec.x);
559 } else if (vec.x < static_cast<T>(0)) {
560 angle = static_cast<T>(M_PI) - ez::atan(-vec.y / vec.x);
561 }
562 return angle - angleOffset;
563 }
564
565 template <typename T>
566 inline std::istream& operator>>(std::istream& vIn, vec2<T>& vType) {
567 char separator;
568 if (vIn >> vType.x >> separator >> vType.y) {
569 if (separator != ';') {
570 vIn.setstate(std::ios::failbit);
571 }
572 }
573 return vIn;
574 }
575
576 template <typename T>
577 inline std::ostream& operator<<(std::ostream& vOut, const vec2<T>& vType) {
578 vOut << vType.x << ";" << vType.y;
579 return vOut;
580 }
581
582 } // namespace ez
583

Directory: include/ezlibs/
File: ezAABBCC.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 23 23 100.0%
Functions: 5 5 100.0%
Branches: 0 0 -%
Decisions: 0 0 -%
Calls: 19 19 100.0%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezAABBCC is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 namespace ez {
30
31 template <typename T>
32 struct AABBCC // copy of b2AABB struct
33 {
34 vec3<T> lowerBound; ///< the lower left vertex
35 vec3<T> upperBound; ///< the upper right vertex
36
37
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
20 AABBCC() : lowerBound((T)0), upperBound((T)0) {
38 20 }
39 1 AABBCC(vec3<T> vlowerBound, vec3<T> vUpperBound)
40 //: lowerBound(vlowerBound), upperBound(vUpperBound)
41
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 {
42
1/1
✓ Call 0 invoked.
1 lowerBound.x = mini(vlowerBound.x, vUpperBound.x);
43
1/1
✓ Call 0 invoked.
1 lowerBound.y = mini(vlowerBound.y, vUpperBound.y);
44
1/1
✓ Call 0 invoked.
1 lowerBound.z = mini(vlowerBound.z, vUpperBound.z);
45
1/1
✓ Call 0 invoked.
1 upperBound.x = maxi(vlowerBound.x, vUpperBound.x);
46
1/1
✓ Call 0 invoked.
1 upperBound.y = maxi(vlowerBound.y, vUpperBound.y);
47
1/1
✓ Call 0 invoked.
1 upperBound.z = maxi(vlowerBound.z, vUpperBound.z);
48 1 }
49
50 /// Verify that the bounds are sorted.
51 // bool IsValid() const;
52
53 /// Add a vector to this vector.
54 void operator+=(const vec3<T>& v) {
55 lowerBound += v;
56 upperBound += v;
57 }
58
59 /// Subtract a vector from this vector.
60 void operator-=(const vec3<T>& v) {
61 lowerBound -= v;
62 upperBound -= v;
63 }
64
65 /// Multiply this vector by a scalar.
66 void operator*=(T a) {
67 lowerBound *= a;
68 upperBound *= a;
69 }
70
71 /// Divide this vector by a scalar.
72 void operator/=(T a) {
73 lowerBound /= a;
74 upperBound /= a;
75 }
76
77 /// Get the center of the AABB.
78 20 vec3<T> GetCenter() const {
79
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
20 return (lowerBound + upperBound) / (T)2;
80 }
81
82 /// Get the extents of the AABB (half-widths).
83 vec3<T> GetExtents() const {
84 return (upperBound - lowerBound) / (T)2;
85 }
86
87 /// Get the perimeter length
88 T GetPerimeter() const {
89 const float wx = upperBound.x - lowerBound.x;
90 const float wy = upperBound.y - lowerBound.y;
91 const float wz = upperBound.z - lowerBound.z;
92 return (T)2 * (wx + wy + wz);
93 }
94
95 /// Combine an AABB into this one.
96 void Combine(const AABBCC<T>& aabb) {
97 lowerBound = mini(lowerBound, aabb.lowerBound);
98 upperBound = maxi(upperBound, aabb.upperBound);
99 }
100
101 /// Combine two AABBs into this one.
102 void Combine(const AABBCC<T>& aabb1, const AABBCC<T>& aabb2) {
103 lowerBound = mini(aabb1.lowerBound, aabb2.lowerBound);
104 upperBound = maxi(aabb1.upperBound, aabb2.upperBound);
105 }
106
107 /// Combine a point into this one.
108 3228840 void Combine(const vec3<T>& pt) {
109
1/1
✓ Call 0 invoked.
3228840 lowerBound.x = mini(lowerBound.x, pt.x);
110
1/1
✓ Call 0 invoked.
3228840 lowerBound.y = mini(lowerBound.y, pt.y);
111
1/1
✓ Call 0 invoked.
3228840 lowerBound.z = mini(lowerBound.z, pt.z);
112
1/1
✓ Call 0 invoked.
3228840 upperBound.x = maxi(upperBound.x, pt.x);
113
1/1
✓ Call 0 invoked.
3228840 upperBound.y = maxi(upperBound.y, pt.y);
114
1/1
✓ Call 0 invoked.
3228840 upperBound.z = maxi(upperBound.z, pt.z);
115 3228840 }
116
117 /// Does this aabb contain the provided AABB.
118 bool Contains(const AABBCC<T>& aabb) const {
119 bool result = true;
120 result &= lowerBound.x <= aabb.lowerBound.x;
121 result &= lowerBound.y <= aabb.lowerBound.y;
122 result &= lowerBound.z <= aabb.lowerBound.z;
123 result &= aabb.upperBound.x <= upperBound.x;
124 result &= aabb.upperBound.y <= upperBound.y;
125 result &= aabb.upperBound.z <= upperBound.z;
126 return result;
127 }
128
129 /// Does this aabb contain the provided vec2<T>.
130 bool ContainsPoint(const vec3<T>& pt) const {
131 bool result = true;
132 result &= lowerBound.x <= pt.x;
133 result &= lowerBound.y <= pt.y;
134 result &= lowerBound.z <= pt.z;
135 result &= pt.x <= upperBound.x;
136 result &= pt.y <= upperBound.y;
137 result &= pt.z <= upperBound.z;
138 return result;
139 }
140
141 bool Intersects(const AABBCC<T>& other) const {
142 bool result = true;
143 result |= lowerBound.x <= other.lowerBound.x;
144 result |= lowerBound.y <= other.lowerBound.y;
145 result |= lowerBound.z <= other.lowerBound.z;
146 result |= other.upperBound.x <= upperBound.x;
147 result |= other.upperBound.y <= upperBound.y;
148 result |= other.upperBound.z <= upperBound.z;
149 return result;
150 }
151
152 21 const vec3<T> Size() const {
153
1/1
✓ Call 0 invoked.
21 return vec3<T>(upperBound - lowerBound);
154 }
155 };
156 typedef AABBCC<double> dAABBCC;
157 typedef AABBCC<float> fAABBCC;
158
159 /// Add a float to a AABBCC<T>.
160 template <typename T>
161 inline AABBCC<T> operator+(const AABBCC<T>& v, float f) {
162 return AABBCC<T>(v.lowerBound + f, v.upperBound + f);
163 }
164
165 /// Add a AABBCC<T> to a AABBCC<T>.
166 template <typename T>
167 inline AABBCC<T> operator+(const AABBCC<T>& v, AABBCC<T> f) {
168 return AABBCC<T>(v.lowerBound + f.lowerBound, v.upperBound + f.upperBound);
169 }
170
171 /// Substract a float from a AABBCC<T>.
172 template <typename T>
173 inline AABBCC<T> operator-(const AABBCC<T>& v, float f) {
174 return AABBCC<T>(v.lowerBound - f, v.upperBound - f);
175 }
176
177 /// Substract a AABBCC<T> to a AABBCC<T>.
178 template <typename T>
179 inline AABBCC<T> operator-(const AABBCC<T>& v, AABBCC<T> f) {
180 return AABBCC<T>(v.lowerBound - f.lowerBound, v.upperBound - f.upperBound);
181 }
182
183 /// Multiply a float with a AABBCC<T>.
184 template <typename T>
185 inline AABBCC<T> operator*(const AABBCC<T>& v, float f) {
186 return AABBCC<T>(v.lowerBound * f, v.upperBound * f);
187 }
188
189 /// Multiply a AABBCC<T> with a AABBCC<T>.
190 template <typename T>
191 inline AABBCC<T> operator*(const AABBCC<T>& v, AABBCC<T> f) {
192 return AABBCC<T>(v.lowerBound * f.lowerBound, v.upperBound * f.upperBound);
193 }
194
195 /// Divide a AABBCC<T> by a float.
196 template <typename T>
197 inline AABBCC<T> operator/(const AABBCC<T>& v, float f) {
198 return AABBCC<T>(v.lowerBound / f, v.upperBound / f);
199 }
200
201 /// Divide a AABBCC<T> by a float.
202 template <typename T>
203 inline AABBCC<T> operator/(AABBCC<T>& v, float f) {
204 return AABBCC<T>(v.lowerBound / f, v.upperBound / f);
205 }
206
207 /// Divide a AABBCC<T> by a AABBCC<T>.
208 template <typename T>
209 inline AABBCC<T> operator/(const AABBCC<T>& v, AABBCC<T> f) {
210 return AABBCC<T>(v.lowerBound / f.lowerBound, v.upperBound / f.upperBound);
211 }
212
213
214 } // namespace ez
215

Directory: include/ezlibs/
File: ezVoxWriter.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 333 355 93.8%
Functions: 49 51 96.1%
Branches: 212 240 88.3%
Decisions: 51 72 70.8%
Calls: 393 449 87.5%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2018-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezVox is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <map>
30 #include <cmath>
31 #include <array>
32 #include <string>
33 #include <vector>
34 #include <chrono>
35 #include <memory>
36 #include <cstdint>
37 #include <sstream>
38 #include <iostream>
39 #include <functional>
40
41 #include "ezMath.hpp"
42 #include "ezStr.hpp"
43
44 // This File is a helper for write a vox file after 0.99 release to support
45 // the world mode editor
46 // just add all color with the color Index with AddColor
47 // And add all voxels with the method AddVoxel with the voxel in world position, and finally save the model
48 // that's all, the file was initially created for my Proecedural soft
49 // it support just my needs for the moment, but i put here because its a basis for more i thinck
50
51 namespace ez {
52 namespace file {
53
54 namespace vox {
55 typedef uint32_t KeyFrame;
56
57 typedef size_t CubeX;
58 typedef size_t CubeY;
59 typedef size_t CubeZ;
60 typedef size_t CubeID;
61 typedef size_t VoxelX;
62 typedef size_t VoxelY;
63 typedef size_t VoxelZ;
64 typedef size_t VoxelID;
65 typedef int32_t TagID;
66 typedef int32_t Version;
67 typedef int32_t ColorID;
68
69 typedef ez::dAABBCC Volume;
70
71 typedef std::function<void(const KeyFrame& vKeyFrame, const double& vValue)> KeyFrameTimeLoggingFunctor;
72
73 200 inline uint32_t GetMVID(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
74 200 return (a) | (b << 8) | (c << 16) | (d << 24);
75 }
76
77 struct DICTstring {
78 int32_t bufferSize = 0;
79 std::string buffer;
80
81
1/1
✓ Call 0 invoked.
198 DICTstring() = default;
82
83 198 void write(FILE* fp) {
84
1/1
✓ Call 0 invoked.
198 bufferSize = (int32_t)buffer.size();
85
1/1
✓ Call 0 invoked.
198 fwrite(&bufferSize, sizeof(int32_t), 1, fp);
86
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
198 fwrite(buffer.data(), sizeof(char), bufferSize, fp);
87 198 }
88 198 size_t getSize() {
89
1/1
✓ Call 0 invoked.
198 bufferSize = (int32_t)buffer.size();
90 198 return sizeof(int32_t) + sizeof(char) * bufferSize;
91 }
92 };
93
94 struct DICTitem {
95 DICTstring key;
96 DICTstring value;
97
98 DICTitem() = default;
99
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
99 DICTitem(std::string vKey, std::string vValue) {
100
1/1
✓ Branch 1 taken 99 times.
1/1
✓ Call 0 invoked.
99 key.buffer = vKey;
101
1/1
✓ Branch 1 taken 99 times.
1/1
✓ Call 0 invoked.
99 value.buffer = vValue;
102
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
99 }
103
104 99 void write(FILE* fp) {
105
1/1
✓ Call 0 invoked.
99 key.write(fp);
106
1/1
✓ Call 0 invoked.
99 value.write(fp);
107 99 }
108
109 99 size_t getSize() {
110
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
99 return key.getSize() + value.getSize();
111 }
112 };
113
114 struct DICT {
115 int32_t count = 0;
116 std::vector<DICTitem> keys;
117
118
1/1
✓ Call 0 invoked.
120 DICT() = default;
119
120 120 void write(FILE* fp) {
121
1/1
✓ Call 0 invoked.
120 count = (int32_t)keys.size();
122
1/1
✓ Call 0 invoked.
120 fwrite(&count, sizeof(int32_t), 1, fp);
123
2/2
✓ Branch 5 taken 99 times.
✓ Branch 6 taken 120 times.
2/2
✓ Decision 'true' taken 99 times.
✓ Decision 'false' taken 120 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
219 for (auto& key : keys) {
124
1/1
✓ Branch 1 taken 99 times.
1/1
✓ Call 0 invoked.
99 key.write(fp);
125 }
126 120 }
127
128 120 size_t getSize() {
129 120 size_t s = sizeof(int32_t);
130
2/2
✓ Branch 4 taken 99 times.
✓ Branch 5 taken 120 times.
2/2
✓ Decision 'true' taken 99 times.
✓ Decision 'false' taken 120 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
219 for (auto& key : keys) {
131
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
99 s += key.getSize();
132 }
133 120 return s;
134 }
135
136 99 void Add(std::string vKey, std::string vValue) {
137
4/4
✓ Branch 1 taken 99 times.
✓ Branch 4 taken 99 times.
✓ Branch 7 taken 99 times.
✓ Branch 10 taken 99 times.
7/10
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 13 invoked.
✓ Call 14 invoked.
✗ Call 15 not invoked.
✗ Call 16 not invoked.
✗ Call 17 not invoked.
99 keys.push_back(DICTitem(vKey, vValue));
138 99 }
139 };
140
141 struct nTRN {
142 int32_t nodeId = 0;
143 DICT nodeAttribs;
144 int32_t childNodeId = 0;
145 int32_t reservedId = -1;
146 int32_t layerId = -1;
147 int32_t numFrames = 1;
148 std::vector<DICT> frames;
149
150
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10 nTRN(int32_t countFrames) {
151 10 numFrames = countFrames;
152
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 frames.resize(static_cast<size_t>(numFrames));
153
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
10 }
154
155 10 void write(FILE* fp) {
156 // chunk header
157
1/1
✓ Call 0 invoked.
10 int32_t id = GetMVID('n', 'T', 'R', 'N');
158
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&id, sizeof(int32_t), 1, fp);
159
1/1
✓ Call 0 invoked.
10 size_t contentSize = getSize();
160
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&contentSize, sizeof(int32_t), 1, fp);
161 10 size_t childSize = 0;
162
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&childSize, sizeof(int32_t), 1, fp);
163
164 // datas's
165
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&nodeId, sizeof(int32_t), 1, fp);
166
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 nodeAttribs.write(fp);
167
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&childNodeId, sizeof(int32_t), 1, fp);
168
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&reservedId, sizeof(int32_t), 1, fp);
169
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&layerId, sizeof(int32_t), 1, fp);
170
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 fwrite(&numFrames, sizeof(int32_t), 1, fp);
171
2/2
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 10 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 10 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
20 for (auto& frame : frames) {
172
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 frame.write(fp);
173 }
174 10 }
175
176 10 size_t getSize() {
177
1/1
✓ Call 0 invoked.
10 size_t s = sizeof(int32_t) * 5 + nodeAttribs.getSize();
178
2/2
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 10 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 10 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
20 for (auto& frame : frames) {
179
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10 s += frame.getSize();
180 }
181 10 return s;
182 }
183 };
184
185 struct nGRP {
186 int32_t nodeId = 0;
187 DICT nodeAttribs;
188 int32_t nodeChildrenNodes;
189 std::vector<int32_t> childNodes;
190
191
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 nGRP(int32_t vCount) {
192 1 nodeChildrenNodes = vCount;
193
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 childNodes.resize(nodeChildrenNodes);
194
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
1 }
195
196 1 void write(FILE* fp) {
197 // chunk header
198
1/1
✓ Call 0 invoked.
1 int32_t id = GetMVID('n', 'G', 'R', 'P');
199
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&id, sizeof(int32_t), 1, fp);
200
1/1
✓ Call 0 invoked.
1 size_t contentSize = getSize();
201
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&contentSize, sizeof(int32_t), 1, fp);
202 1 size_t childSize = 0;
203
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&childSize, sizeof(int32_t), 1, fp);
204
205 // datas's
206
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&nodeId, sizeof(int32_t), 1, fp);
207
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 nodeAttribs.write(fp);
208
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&nodeChildrenNodes, sizeof(int32_t), 1, fp);
209
1/1
✓ Branch 2 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 fwrite(childNodes.data(), sizeof(int32_t), nodeChildrenNodes, fp);
210 1 }
211
212 1 size_t getSize() {
213
1/1
✓ Call 0 invoked.
1 return sizeof(int32_t) * (2 + nodeChildrenNodes) + nodeAttribs.getSize();
214 }
215 };
216
217 struct MODEL {
218 int32_t modelId = 0;
219 DICT modelAttribs;
220
221
1/1
✓ Call 0 invoked.
90 MODEL() = default;
222
223 90 void write(FILE* fp) {
224
1/1
✓ Call 0 invoked.
90 fwrite(&modelId, sizeof(int32_t), 1, fp);
225
1/1
✓ Call 0 invoked.
90 modelAttribs.write(fp);
226 90 }
227
228 90 size_t getSize() {
229
1/1
✓ Call 0 invoked.
90 return sizeof(int32_t) + modelAttribs.getSize();
230 }
231 };
232
233 struct nSHP {
234 int32_t nodeId = 0;
235 DICT nodeAttribs;
236 int32_t numModels;
237 std::vector<MODEL> models;
238
239
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
9 nSHP(int32_t vCount) {
240 9 numModels = vCount;
241
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 models.resize(numModels);
242
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
9 }
243
244 9 void write(FILE* fp) {
245 // chunk header
246
1/1
✓ Call 0 invoked.
9 int32_t id = GetMVID('n', 'S', 'H', 'P');
247
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 fwrite(&id, sizeof(int32_t), 1, fp);
248
1/1
✓ Call 0 invoked.
9 size_t contentSize = getSize();
249
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 fwrite(&contentSize, sizeof(int32_t), 1, fp);
250 9 size_t childSize = 0;
251
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 fwrite(&childSize, sizeof(int32_t), 1, fp);
252
253 // datas's
254
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 fwrite(&nodeId, sizeof(int32_t), 1, fp);
255
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 nodeAttribs.write(fp);
256
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 fwrite(&numModels, sizeof(int32_t), 1, fp);
257
2/2
✓ Branch 5 taken 90 times.
✓ Branch 6 taken 9 times.
2/2
✓ Decision 'true' taken 90 times.
✓ Decision 'false' taken 9 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
99 for (auto& model : models) {
258
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 model.write(fp);
259 }
260 9 }
261
262 9 size_t getSize() {
263
1/1
✓ Call 0 invoked.
9 size_t s = sizeof(int32_t) * 2 + nodeAttribs.getSize();
264
2/2
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 9 times.
2/2
✓ Decision 'true' taken 90 times.
✓ Decision 'false' taken 9 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
99 for (auto& model : models) {
265
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
90 s += model.getSize();
266 }
267 9 return s;
268 }
269 };
270
271 struct LAYR {
272 int32_t nodeId = 0;
273 int32_t reservedId = -1;
274 DICT nodeAttribs;
275
276 LAYR() = default;
277
278 void write(FILE* fp) {
279 // chunk header
280 int32_t id = GetMVID('L', 'A', 'Y', 'R');
281 fwrite(&id, sizeof(int32_t), 1, fp);
282 size_t contentSize = getSize();
283 fwrite(&contentSize, sizeof(int32_t), 1, fp);
284 size_t childSize = 0;
285 fwrite(&childSize, sizeof(int32_t), 1, fp);
286
287 // datas's
288 fwrite(&nodeId, sizeof(int32_t), 1, fp);
289 nodeAttribs.write(fp);
290 fwrite(&reservedId, sizeof(int32_t), 1, fp);
291 }
292
293 size_t getSize() {
294 return sizeof(int32_t) * 2 + nodeAttribs.getSize();
295 }
296 };
297
298 struct SIZE {
299 int32_t sizex = 0;
300 int32_t sizey = 0;
301 int32_t sizez = 0;
302
303 9 SIZE() = default;
304
305 90 void write(FILE* fp) {
306 // chunk header
307
1/1
✓ Call 0 invoked.
90 int32_t id = GetMVID('S', 'I', 'Z', 'E');
308
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&id, sizeof(int32_t), 1, fp);
309
1/1
✓ Call 0 invoked.
90 size_t contentSize = getSize();
310
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&contentSize, sizeof(int32_t), 1, fp);
311 90 size_t childSize = 0;
312
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&childSize, sizeof(int32_t), 1, fp);
313
314 // datas's
315
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&sizex, sizeof(int32_t), 1, fp);
316
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&sizey, sizeof(int32_t), 1, fp);
317
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&sizez, sizeof(int32_t), 1, fp);
318 90 }
319
320 90 size_t getSize() {
321 90 return sizeof(int32_t) * 3;
322 }
323 };
324
325 struct XYZI {
326 int32_t numVoxels = 0;
327 std::vector<uint8_t> voxels;
328
329
1/1
✓ Call 0 invoked.
90 XYZI() = default;
330
331 90 void write(FILE* fp) {
332 // chunk header
333
1/1
✓ Call 0 invoked.
90 int32_t id = GetMVID('X', 'Y', 'Z', 'I');
334
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&id, sizeof(int32_t), 1, fp);
335
1/1
✓ Call 0 invoked.
90 size_t contentSize = getSize();
336
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&contentSize, sizeof(int32_t), 1, fp);
337 90 size_t childSize = 0;
338
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&childSize, sizeof(int32_t), 1, fp);
339
340 // datas's
341
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 fwrite(&numVoxels, sizeof(int32_t), 1, fp);
342
1/1
✓ Branch 3 taken 90 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
90 fwrite(voxels.data(), sizeof(uint8_t), voxels.size(), fp);
343 90 }
344
345 90 size_t getSize() {
346
1/1
✓ Call 0 invoked.
90 numVoxels = (int32_t)voxels.size() / 4;
347 90 return sizeof(int32_t) * (1 + numVoxels);
348 }
349 };
350
351 struct RGBA {
352 std::array<int32_t, 256> colors{};
353
354 RGBA() = default;
355
356 void write(FILE* fp) {
357 // chunk header
358
0/1
✗ Call 0 not invoked.
int32_t id = GetMVID('R', 'G', 'B', 'A');
359
0/1
✗ Call 0 not invoked.
fwrite(&id, sizeof(int32_t), 1, fp);
360
0/1
✗ Call 0 not invoked.
size_t contentSize = getSize();
361
0/1
✗ Call 0 not invoked.
fwrite(&contentSize, sizeof(int32_t), 1, fp);
362 size_t childSize = 0;
363
0/1
✗ Call 0 not invoked.
fwrite(&childSize, sizeof(int32_t), 1, fp);
364
365 // datas's
366
0/1
✗ Call 0 not invoked.
fwrite(colors.data(), sizeof(uint8_t), contentSize, fp);
367 }
368
369 size_t getSize() {
370 return sizeof(int32_t) * colors.size();
371 }
372 };
373
374 struct VoxCube {
375 int id = 0;
376
377 // translate
378 int tx = 0;
379 int ty = 0;
380 int tz = 0;
381
382 SIZE size;
383 std::map<KeyFrame, XYZI> xyzis;
384
385
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
9 VoxCube() = default;
386
387 9 void write(FILE* fp) {
388
2/2
✓ Branch 5 taken 90 times.
✓ Branch 6 taken 9 times.
2/2
✓ Decision 'true' taken 90 times.
✓ Decision 'false' taken 9 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
99 for (auto& xyzi : xyzis) {
389
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 size.write(fp);
390
1/1
✓ Branch 1 taken 90 times.
1/1
✓ Call 0 invoked.
90 xyzi.second.write(fp);
391 }
392 9 }
393 };
394
395 class Writer {
396 private:
397 9 static const uint32_t GetID(const uint8_t& a, const uint8_t& b, const uint8_t& c, const uint8_t& d) {
398 9 return (a) | (b << 8) | (c << 16) | (d << 24);
399 }
400
401 private:
402 Version MV_VERSION = 150; // the old version of MV not open another file than if version is 150 (answer by @ephtracy)
403
404 1 TagID ID_VOX = GetID('V', 'O', 'X', ' ');
405 1 TagID ID_PACK = GetID('P', 'A', 'C', 'K');
406 1 TagID ID_MAIN = GetID('M', 'A', 'I', 'N');
407 1 TagID ID_SIZE = GetID('S', 'I', 'Z', 'E');
408 1 TagID ID_XYZI = GetID('X', 'Y', 'Z', 'I');
409 1 TagID ID_RGBA = GetID('R', 'G', 'B', 'A');
410 1 TagID ID_NTRN = GetID('n', 'T', 'R', 'N');
411 1 TagID ID_NGRP = GetID('n', 'G', 'R', 'P');
412 1 TagID ID_NSHP = GetID('n', 'S', 'H', 'P');
413
414 VoxelX m_MaxVoxelPerCubeX = 0;
415 VoxelY m_MaxVoxelPerCubeY = 0;
416 VoxelZ m_MaxVoxelPerCubeZ = 0;
417
418 CubeID maxCubeId = 0;
419 CubeX minCubeX = (CubeX)1e7;
420 CubeY minCubeY = (CubeY)1e7;
421 CubeZ minCubeZ = (CubeZ)1e7;
422
423 FILE* m_File = nullptr;
424
425 Volume maxVolume = Volume(1e7, -1e7);
426
427 KeyFrame m_KeyFrame = 0;
428
429 std::vector<ColorID> colors;
430
431 std::vector<VoxCube> cubes;
432
433 std::map<CubeX, std::map<CubeY, std::map<CubeZ, CubeID>>> cubesId;
434 std::map<KeyFrame, std::map<VoxelX, std::map<VoxelY, std::map<VoxelZ, VoxelID>>>> voxelId;
435
436 int32_t lastError = 0;
437
438 bool m_TimeLoggingEnabled = false; // for log elapsed time between key frames and total
439
440 std::chrono::steady_clock::time_point m_StartTime;
441 std::chrono::steady_clock::time_point m_LastKeyFrameTime;
442 std::map<KeyFrame, double> m_FrameTimes;
443 double m_TotalTime = 0.0;
444
445 KeyFrameTimeLoggingFunctor m_KeyFrameTimeLoggingFunctor;
446
447 public:
448 //////////////////////////////////////////////////////////////////
449 // the limit of magicavoxel is 127 for one cube, is 127 voxels (indexs : 0 -> 126)
450 // vMaxVoxelPerCubeX,Y,Z define the limit of one cube
451
2/2
✓ Branch 1 taken 1 times.
✓ Branch 16 taken 1 times.
22/22
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✓ Call 11 invoked.
✓ Call 12 invoked.
✓ Call 13 invoked.
✓ Call 14 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✓ Call 19 invoked.
✓ Call 20 invoked.
✓ Call 21 invoked.
✓ Call 22 invoked.
✓ Call 23 invoked.
✓ Call 24 invoked.
✓ Call 25 invoked.
2 Writer(const VoxelX& vMaxVoxelPerCubeX = 126, const VoxelY& vMaxVoxelPerCubeY = 126, const VoxelZ& vMaxVoxelPerCubeZ = 126) {
452 // the limit of magicavoxel is 127 because the first voxel is 1 not 0
453 // so this is 0 to 126
454 // index limit, size is 127
455
1/1
✓ Call 0 invoked.
1 m_MaxVoxelPerCubeX = ez::clamp<size_t>(vMaxVoxelPerCubeX, 0, 126);
456
1/1
✓ Call 0 invoked.
1 m_MaxVoxelPerCubeY = ez::clamp<size_t>(vMaxVoxelPerCubeY, 0, 126);
457
1/1
✓ Call 0 invoked.
1 m_MaxVoxelPerCubeZ = ez::clamp<size_t>(vMaxVoxelPerCubeZ, 0, 126);
458 1 }
459
460
6/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
1 ~Writer() = default;
461
462 Writer& clear() {
463 clearVoxels();
464 clearColors();
465 return *this;
466 }
467
468 Writer& clearVoxels() {
469 cubes.clear();
470 cubesId.clear();
471 voxelId.clear();
472 return *this;
473 }
474
475 Writer& clearColors() {
476 colors.clear();
477 return *this;
478 }
479
480 1 Writer& startTimeLogging() {
481 1 m_TimeLoggingEnabled = true;
482
1/1
✓ Call 0 invoked.
1 m_StartTime = std::chrono::steady_clock::now();
483 1 m_LastKeyFrameTime = m_StartTime;
484 1 return *this;
485 };
486
487 1 Writer& stopTimeLogging() {
488
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (m_TimeLoggingEnabled) {
489
1/1
✓ Call 0 invoked.
1 const auto now = std::chrono::steady_clock::now();
490
3/3
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 8 taken 1 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
1 m_FrameTimes[m_KeyFrame] = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_LastKeyFrameTime).count() * 1e-3;
491
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (m_KeyFrameTimeLoggingFunctor) {
492
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
1 m_KeyFrameTimeLoggingFunctor(m_KeyFrame, m_FrameTimes.at(m_KeyFrame));
493 }
494
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
1 m_TotalTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_StartTime).count() * 1e-3;
495 1 m_TimeLoggingEnabled = false;
496 }
497 1 return *this;
498 }
499
500 1 Writer& setKeyFrameTimeLoggingFunctor(const KeyFrameTimeLoggingFunctor& vKeyFrameTimeLoggingFunctor) {
501
1/1
✓ Call 0 invoked.
1 m_KeyFrameTimeLoggingFunctor = vKeyFrameTimeLoggingFunctor;
502 1 return *this;
503 }
504
505 10 Writer& setKeyFrame(uint32_t vKeyFrame) {
506
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 times.
10 if (m_KeyFrame != vKeyFrame) {
507
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 9 times.
✗ Decision 'false' not taken.
9 if (m_TimeLoggingEnabled) {
508
1/1
✓ Call 0 invoked.
9 const auto now = std::chrono::steady_clock::now();
509
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 const auto elapsed = now - m_LastKeyFrameTime;
510
2/2
✓ Branch 1 taken 9 times.
✓ Branch 5 taken 9 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
9 m_FrameTimes[m_KeyFrame] = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count() * 1e-3;
511
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 9 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
9 if (m_KeyFrameTimeLoggingFunctor) {
512
2/2
✓ Branch 1 taken 9 times.
✓ Branch 4 taken 9 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
9 m_KeyFrameTimeLoggingFunctor(m_KeyFrame, m_FrameTimes.at(m_KeyFrame));
513 }
514 9 m_LastKeyFrameTime = now;
515 }
516 9 m_KeyFrame = vKeyFrame;
517 }
518 10 return *this;
519 }
520
521 Writer& addColor(const uint8_t& r, const uint8_t& g, const uint8_t& b, const uint8_t& a, const uint8_t& index) {
522 while (colors.size() <= index)
523 colors.push_back(0);
524 colors[index] = GetID(r, g, b, a);
525 return *this;
526 }
527
528 1428840 Writer& addVoxel(const size_t& vX, const size_t& vY, const size_t& vZ, const uint8_t& vColorIndex) {
529 // cube pos
530 1428840 size_t ox = (size_t)std::floor((double)vX / (double)m_MaxVoxelPerCubeX);
531 1428840 size_t oy = (size_t)std::floor((double)vY / (double)m_MaxVoxelPerCubeY);
532 1428840 size_t oz = (size_t)std::floor((double)vZ / (double)m_MaxVoxelPerCubeZ);
533
534
1/1
✓ Call 0 invoked.
1428840 minCubeX = ez::mini<size_t>(minCubeX, ox);
535
1/1
✓ Call 0 invoked.
1428840 minCubeY = ez::mini<size_t>(minCubeX, oy);
536
1/1
✓ Call 0 invoked.
1428840 minCubeZ = ez::mini<size_t>(minCubeX, oz);
537
538
1/1
✓ Branch 1 taken 1428840 times.
1/1
✓ Call 0 invoked.
1428840 auto cube = m_GetCube(ox, oy, oz);
539
540
1/1
✓ Branch 1 taken 1428840 times.
1/1
✓ Call 0 invoked.
1428840 m_MergeVoxelInCube(vX, vY, vZ, vColorIndex, cube);
541 1428840 return *this;
542 }
543
544 1 Writer& save(const std::string& vFilePathName) {
545
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (m_OpenFileForWriting(vFilePathName)) {
546 1 int32_t zero = 0;
547
548
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&ID_VOX, sizeof(int32_t), 1, m_File);
549
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&MV_VERSION, sizeof(int32_t), 1, m_File);
550
551 // MAIN CHUNCK
552
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&ID_MAIN, sizeof(int32_t), 1, m_File);
553
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&zero, sizeof(int32_t), 1, m_File);
554
555
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 long numBytesMainChunkPos = m_GetFilePos();
556
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&zero, sizeof(int32_t), 1, m_File);
557
558
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 long headerSize = m_GetFilePos();
559
560
1/1
✓ Call 0 invoked.
1 int count = (int)cubes.size();
561
562 1 int nodeIds = 0;
563
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 nTRN rootTransform(1);
564 1 rootTransform.nodeId = nodeIds;
565 1 rootTransform.childNodeId = ++nodeIds;
566
567
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 nGRP rootGroup(count);
568 1 rootGroup.nodeId = nodeIds; //
569 1 rootGroup.nodeChildrenNodes = count;
570
571
1/1
✓ Call 0 invoked.
1 std::vector<nSHP> shapes;
572
1/1
✓ Call 0 invoked.
1 std::vector<nTRN> shapeTransforms;
573 1 size_t cube_idx = 0U;
574 1 int32_t model_id = 0U;
575
2/2
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
10 for (auto& cube : cubes) {
576
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 cube.write(m_File);
577
578 // trans
579
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 nTRN trans(1); // not a trans anim so ony one frame
580 9 trans.nodeId = ++nodeIds; //
581
1/1
✓ Call 0 invoked.
9 rootGroup.childNodes[cube_idx] = nodeIds;
582 9 trans.childNodeId = ++nodeIds;
583 9 trans.layerId = 0;
584
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 cube.tx = (int)std::floor((cube.tx - minCubeX + 0.5f) * m_MaxVoxelPerCubeX - maxVolume.lowerBound.x - maxVolume.Size().x * 0.5);
585
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 cube.ty = (int)std::floor((cube.ty - minCubeY + 0.5f) * m_MaxVoxelPerCubeY - maxVolume.lowerBound.y - maxVolume.Size().y * 0.5);
586
1/1
✓ Call 0 invoked.
9 cube.tz = (int)std::floor((cube.tz - minCubeZ + 0.5f) * m_MaxVoxelPerCubeZ);
587
9/9
✓ Branch 2 taken 9 times.
✓ Branch 5 taken 9 times.
✓ Branch 8 taken 9 times.
✓ Branch 11 taken 9 times.
✓ Branch 14 taken 9 times.
✓ Branch 17 taken 9 times.
✓ Branch 20 taken 9 times.
✓ Branch 23 taken 9 times.
✓ Branch 26 taken 9 times.
18/26
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 16 invoked.
✓ Call 19 invoked.
✓ Call 22 invoked.
✓ Call 25 invoked.
✓ Call 28 invoked.
✓ Call 29 invoked.
✓ Call 30 invoked.
✓ Call 31 invoked.
✓ Call 32 invoked.
✓ Call 33 invoked.
✓ Call 34 invoked.
✓ Call 35 invoked.
✗ Call 36 not invoked.
✗ Call 37 not invoked.
✗ Call 38 not invoked.
✗ Call 39 not invoked.
✗ Call 40 not invoked.
✗ Call 41 not invoked.
✗ Call 42 not invoked.
✗ Call 43 not invoked.
27 trans.frames[0].Add("_t", ez::str::toStr(cube.tx) + " " + ez::str::toStr(cube.ty) + " " + ez::str::toStr(cube.tz));
588
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 shapeTransforms.push_back(trans);
589
590 // shape
591
1/1
✓ Branch 2 taken 9 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
9 nSHP shape((int32_t)cube.xyzis.size());
592 9 shape.nodeId = nodeIds;
593 9 size_t model_array_id = 0U;
594
2/2
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 9 times.
2/2
✓ Decision 'true' taken 90 times.
✓ Decision 'false' taken 9 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
99 for (const auto& xyzi : cube.xyzis) {
595
1/1
✓ Call 0 invoked.
90 shape.models[model_array_id].modelId = model_id;
596
3/3
✓ Branch 2 taken 90 times.
✓ Branch 5 taken 90 times.
✓ Branch 8 taken 90 times.
6/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 11 invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
270 shape.models[model_array_id].modelAttribs.Add("_f", ez::str::toStr(xyzi.first));
597 90 ++model_array_id;
598
1/1
✓ Call 0 invoked.
90 ++model_id;
599 }
600
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 shapes.push_back(shape);
601
602 9 ++cube_idx;
603
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
9 }
604
605
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 rootTransform.write(m_File);
606
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 rootGroup.write(m_File);
607
608 // trn & shp
609
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 times.
10 for (int i = 0; i < count; i++) {
610
1/1
✓ Branch 2 taken 9 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
9 shapeTransforms[i].write(m_File);
611
1/1
✓ Branch 2 taken 9 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
9 shapes[i].write(m_File);
612 }
613
614 // no layr in my cases
615
616 // layr
617 /*for (int i = 0; i < 8; i++)
618 {
619 LAYR layr;
620 layr.nodeId = i;
621 layr.nodeAttribs.Add("_name", ez::str::toStr(i));
622 layr.write(m_File);
623 }*/
624
625 // RGBA Palette
626
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1/1
✓ Call 0 invoked.
1 if (colors.size() > 0) {
627 RGBA palette;
628
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (int32_t i = 0; i < 255; i++) {
629
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/1
✗ Call 0 not invoked.
if (i < (int32_t)colors.size()) {
630
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
palette.colors[i] = colors[i];
631 } else {
632
0/1
✗ Call 0 not invoked.
palette.colors[i] = 0;
633 }
634 }
635
636
0/1
✗ Call 0 not invoked.
palette.write(m_File);
637 }
638
639
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 const long mainChildChunkSize = m_GetFilePos() - headerSize;
640
1/1
✓ Call 0 invoked.
1 m_SetFilePos(numBytesMainChunkPos);
641 1 uint32_t size = (uint32_t)mainChildChunkSize;
642
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 fwrite(&size, sizeof(uint32_t), 1, m_File);
643
644
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 m_CloseFile();
645
4/8
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
1 }
646 1 return *this;
647 }
648
649 size_t getVoxelsCount(const KeyFrame& vKeyFrame) const {
650 size_t voxel_count = 0U;
651 for (const auto& cube : cubes) {
652 if (cube.xyzis.find(vKeyFrame) != cube.xyzis.end()) {
653 voxel_count += cube.xyzis.at(vKeyFrame).numVoxels;
654 }
655 }
656 return voxel_count;
657 }
658
659 size_t getVoxelsCount() const {
660 size_t voxel_count = 0U;
661 for (const auto& cube : cubes) {
662 for (auto& key_xyzi : cube.xyzis) {
663 voxel_count += key_xyzi.second.numVoxels;
664 }
665 }
666 return voxel_count;
667 }
668
669 1 Writer& printStats() {
670
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
1 std::cout << "---- Stats ------------------------------" << std::endl;
671
10/10
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 16 taken 1 times.
✓ Branch 19 taken 1 times.
✓ Branch 22 taken 1 times.
✓ Branch 25 taken 1 times.
✓ Branch 28 taken 1 times.
10/10
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✓ Call 21 invoked.
✓ Call 24 invoked.
✓ Call 27 invoked.
1 std::cout << "Volume : " << maxVolume.Size().x << " x " << maxVolume.Size().y << " x " << maxVolume.Size().z << std::endl;
672
3/3
✓ Branch 1 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
1 std::cout << "count cubes : " << cubes.size() << std::endl;
673
1/1
✓ Call 0 invoked.
1 std::map<KeyFrame, size_t> frame_counts;
674
2/2
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
10 for (const auto& cube : cubes) {
675
2/2
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 9 times.
2/2
✓ Decision 'true' taken 90 times.
✓ Decision 'false' taken 9 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
99 for (auto& key_xyzi : cube.xyzis) {
676
1/1
✓ Branch 1 taken 90 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
90 frame_counts[key_xyzi.first] += key_xyzi.second.numVoxels;
677 }
678 }
679 1 size_t voxels_total = 0U;
680
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (frame_counts.size() > 1U) {
681
3/3
✓ Branch 1 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
1 std::cout << "count key frames : " << frame_counts.size() << std::endl;
682
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
1 std::cout << "-----------------------------------------" << std::endl;
683
2/2
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 1 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 1 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
11 for (const auto& frame_count : frame_counts) {
684
3/3
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
✓ Branch 7 taken 10 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
10 std::cout << " o--\\-> key frame : " << frame_count.first << std::endl;
685
3/3
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
✓ Branch 7 taken 10 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
10 std::cout << " \\-> voxels count : " << frame_count.second << std::endl;
686
2/3
✓ Branch 2 taken 10 times.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
1/2
✓ Decision 'true' taken 10 times.
✗ Decision 'false' not taken.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
10 if (m_FrameTimes.find(frame_count.first) != m_FrameTimes.end()) {
687
5/5
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
✓ Branch 7 taken 10 times.
✓ Branch 10 taken 10 times.
✓ Branch 13 taken 10 times.
5/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
10 std::cout << " \\-> elapsed time : " << m_FrameTimes.at(frame_count.first) << " secs" << std::endl;
688 }
689
1/1
✓ Call 0 invoked.
10 voxels_total += frame_count.second;
690 }
691
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
1 std::cout << "-----------------------------------------" << std::endl;
692
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/1
✗ Call 0 not invoked.
} else if (!frame_counts.empty()) {
693
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
voxels_total = frame_counts.begin()->second;
694 }
695
3/3
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
1 std::cout << "voxels total : " << voxels_total << std::endl;
696
4/4
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
1 std::cout << "total elapsed time : " << m_TotalTime << " secs" << std::endl;
697
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
1 std::cout << "-----------------------------------------" << std::endl;
698 1 return *this;
699
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
1 }
700
701 private:
702 1 bool m_OpenFileForWriting(const std::string& vFilePathName) {
703 #if _MSC_VER
704 lastError = fopen_s(&m_File, vFilePathName.c_str(), "wb");
705 #else
706
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 m_File = fopen(vFilePathName.c_str(), "wb");
707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 lastError = m_File ? 0 : errno;
708 #endif
709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (lastError != 0) return false;
710 1 return true;
711 }
712
713 1 void m_CloseFile() {
714
1/1
✓ Call 0 invoked.
1 fclose(m_File);
715 1 }
716
717 3 long m_GetFilePos() const {
718
1/1
✓ Call 0 invoked.
3 return ftell(m_File);
719 }
720
721 1 void m_SetFilePos(const long& vPos) {
722 // SEEK_SET Beginning of file
723 // SEEK_CUR Current position of the file pointer
724 // SEEK_END End of file
725
1/1
✓ Call 0 invoked.
1 fseek(m_File, vPos, SEEK_SET);
726 1 }
727
728 1428840 const size_t m_GetCubeId(const VoxelX& vX, const VoxelY& vY, const VoxelZ& vZ) {
729
3/3
✓ Branch 2 taken 1428840 times.
✓ Branch 5 taken 1428837 times.
✓ Branch 6 taken 3 times.
2/2
✓ Decision 'true' taken 1428837 times.
✓ Decision 'false' taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 7 not invoked.
1428840 if (cubesId.find(vX) != cubesId.end()) {
730
5/5
✓ Branch 1 taken 1428837 times.
✓ Branch 5 taken 1428837 times.
✓ Branch 8 taken 1428837 times.
✓ Branch 11 taken 1428831 times.
✓ Branch 12 taken 6 times.
2/2
✓ Decision 'true' taken 1428831 times.
✓ Decision 'false' taken 6 times.
5/6
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✗ Call 13 not invoked.
1428837 if (cubesId[vX].find(vY) != cubesId[vX].end()) {
731
6/7
✓ Branch 1 taken 1428831 times.
✓ Branch 4 taken 1428831 times.
✓ Branch 8 taken 1428831 times.
✓ Branch 11 taken 1428831 times.
✓ Branch 14 taken 1428831 times.
✓ Branch 17 taken 1428831 times.
✗ Branch 18 not taken.
1/2
✓ Decision 'true' taken 1428831 times.
✗ Decision 'false' not taken.
7/7
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 16 invoked.
1428831 if (cubesId[vX][vY].find(vZ) != cubesId[vX][vY].end()) {
732
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1428831 return cubesId[vX][vY][vZ];
733 }
734 }
735 }
736
737
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
9 cubesId[vX][vY][vZ] = maxCubeId++;
738
739
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
9 return cubesId[vX][vY][vZ];
740 }
741
742 // Wrap a position inside a particular cube dimension
743 4286520 inline uint8_t Wrap(size_t v, size_t lim) {
744 4286520 v = v % lim;
745 if (v < 0) {
746 v += lim;
747 }
748 4286520 return (uint8_t)v;
749 }
750
751 1428840 void m_MergeVoxelInCube(const VoxelX& vX, const VoxelY& vY, const VoxelZ& vZ, const uint8_t& vColorIndex, VoxCube* vCube) {
752
1/1
✓ Branch 2 taken 1428840 times.
2/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
1428840 maxVolume.Combine(ez::dvec3((double)vX, (double)vY, (double)vZ));
753
754 1428840 bool exist = false;
755
3/3
✓ Branch 2 taken 1428840 times.
✓ Branch 5 taken 1428830 times.
✓ Branch 6 taken 10 times.
2/2
✓ Decision 'true' taken 1428830 times.
✓ Decision 'false' taken 10 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 7 not invoked.
1428840 if (voxelId.find(m_KeyFrame) != voxelId.end()) {
756
1/1
✓ Call 0 invoked.
1428830 auto& vidk = voxelId.at(m_KeyFrame);
757
3/3
✓ Branch 2 taken 1428830 times.
✓ Branch 5 taken 1425060 times.
✓ Branch 6 taken 3770 times.
2/2
✓ Decision 'true' taken 1425060 times.
✓ Decision 'false' taken 3770 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 7 not invoked.
1428830 if (vidk.find(vX) != vidk.end()) {
758
1/1
✓ Call 0 invoked.
1425060 auto& vidkx = vidk.at(vX);
759
2/3
✓ Branch 2 taken 1425060 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1425060 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1425060 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 7 not invoked.
1425060 if (vidkx.find(vY) != vidkx.end()) {
760
0/1
✗ Call 0 not invoked.
auto& vidkxy = vidkx.at(vY);
761
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
if (vidkxy.find(vZ) != vidkxy.end()) {
762 exist = true;
763 }
764 }
765 }
766 }
767
768
1/2
✓ Branch 0 taken 1428840 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1428840 times.
✗ Decision 'false' not taken.
1428840 if (!exist) {
769
1/1
✓ Call 0 invoked.
1428840 auto& xyzi = vCube->xyzis[m_KeyFrame];
770
1/1
✓ Branch 2 taken 1428840 times.
2/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
1428840 xyzi.voxels.push_back(Wrap(vX, m_MaxVoxelPerCubeX)); // x
771
1/1
✓ Branch 2 taken 1428840 times.
2/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
1428840 xyzi.voxels.push_back(Wrap(vY, m_MaxVoxelPerCubeY)); // y
772
1/1
✓ Branch 2 taken 1428840 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1428840 xyzi.voxels.push_back(Wrap(vZ, m_MaxVoxelPerCubeZ)); // z
773
774 // correspond a la loc de la couleur du voxel en question
775
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
1428840 voxelId[m_KeyFrame][vX][vY][vZ] = (int)xyzi.voxels.size();
776
777
1/1
✓ Call 0 invoked.
1428840 xyzi.voxels.push_back(vColorIndex); // color index
778 }
779 1428840 }
780
781 1428840 VoxCube* m_GetCube(const VoxelX& vX, const VoxelY& vY, const VoxelZ& vZ) {
782
1/1
✓ Branch 1 taken 1428840 times.
1/1
✓ Call 0 invoked.
1428840 const auto& id = m_GetCubeId(vX, vY, vZ);
783
784
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1428831 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1428831 times.
1/1
✓ Call 0 invoked.
1428840 if (id == cubes.size()) {
785
1/1
✓ Call 0 invoked.
9 VoxCube c;
786
787 9 c.id = (int32_t)id;
788
789 9 c.tx = (int32_t)vX;
790 9 c.ty = (int32_t)vY;
791 9 c.tz = (int32_t)vZ;
792
793 9 c.size.sizex = (int32_t)m_MaxVoxelPerCubeX;
794 9 c.size.sizey = (int32_t)m_MaxVoxelPerCubeY;
795 9 c.size.sizez = (int32_t)m_MaxVoxelPerCubeZ;
796
797
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 cubes.push_back(c);
798
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
9 }
799
800
1/2
✓ Branch 1 taken 1428840 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1428840 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1428840 if (id < cubes.size()) {
801
1/1
✓ Call 0 invoked.
1428840 return &cubes[id];
802 }
803
804 return nullptr;
805 }
806 };
807
808 } // namespace vox
809 } // namespace file
810 } // namespace ez
811

Directory: include/ezlibs/
File: ezVec3.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 58 59 98.3%
Functions: 143 143 100.0%
Branches: 28 39 71.8%
Decisions: 1 2 50.0%
Calls: 41 47 87.2%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 #ifndef EZ_TOOLS_VEC3
4 #define EZ_TOOLS_VEC3
5 #endif // EZ_TOOLS_VEC3
6
7 /*
8 MIT License
9
10 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 */
30
31 // ezVec3 is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
32
33 #include <type_traits>
34 #include <cmath>
35 #include <string>
36 #include <vector>
37
38 namespace ez {
39
40 // Restrict the template to relevant types only (e.g., disable bool)
41 template <typename T>
42 struct vec3 {
43 static_assert(!std::is_same<T, bool>::value, "vec3 cannot be instantiated with bool type");
44
45 T x = static_cast<T>(0), y = static_cast<T>(0), z = static_cast<T>(0);
46
47 // Default constructor
48 14 vec3() : x(static_cast<T>(0)), y(static_cast<T>(0)), z(static_cast<T>(0)) {}
49
50 // Constructor with type conversion
51 template <typename U>
52 vec3(const vec3<U>& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)), z(static_cast<T>(a.z)) {}
53
54 // Constructor with type conversion
55 template <typename U>
56 vec3(const U& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)), z(static_cast<T>(a.z)) {}
57
58 // Constructor for uniform initialization
59 42 vec3(T xyz) : x(xyz), y(xyz), z(xyz) {}
60
61 // Constructor with specific values
62 3229289 vec3(T x, T y, T z) : x(x), y(y), z(z) {}
63
64 // Constructor using a vec2 and a scalar
65 // Assumption: vec2<T> is defined elsewhere, as it is referenced but not included here.
66 vec3(const vec2<T>& xy, T z) : x(xy.x), y(xy.y), z(z) {}
67
68 // Constructor from string
69 vec3(const std::string& vec, char c = ';', vec3<T>* def = nullptr) {
70 if (def) {
71 x = def->x;
72 y = def->y;
73 z = def->z;
74 }
75 std::vector<T> result = str::stringToNumberVector<T>(vec, c);
76 const size_t s = result.size();
77 if (s > 0)
78 x = result[0];
79 if (s > 1)
80 y = result[1];
81 if (s > 2)
82 z = result[2];
83 }
84
85 // Indexing operator
86 T& operator[](size_t i) { return (&x)[i]; }
87
88 // Offset the vector
89
1/1
✓ Call 0 invoked.
12 vec3 Offset(T vX, T vY, T vZ) const { return vec3(x + vX, y + vY, z + vZ); }
90
91 // Set the vector's components
92 12 void Set(T vX, T vY, T vZ) {
93 12 x = vX;
94 12 y = vY;
95 12 z = vZ;
96 12 }
97
98 operator vec2<T>() const { return vec2<T>(x, y); }
99
100 // Negation operator
101 8 vec3 operator-() const {
102 static_assert(std::is_signed<T>::value, "Negate is only valid for signed types");
103
1/1
✓ Call 0 invoked.
8 return vec3(-x, -y, -z);
104 }
105
106 // Logical NOT operator, only for integral types
107 4 vec3 operator!() const {
108 static_assert(std::is_integral<T>::value, "Logical NOT is only valid for integral types");
109
1/1
✓ Call 0 invoked.
4 return vec3(!x, !y, !z);
110 }
111
112 // Extract 2D vectors from 3D vector
113
1/1
✓ Call 0 invoked.
12 vec2<T> xy() const { return vec2<T>(x, y); }
114
115
1/1
✓ Call 0 invoked.
12 vec2<T> xz() const { return vec2<T>(x, z); }
116
117
1/1
✓ Call 0 invoked.
12 vec2<T> yz() const { return vec2<T>(y, z); }
118
119 // Cyclic permutation
120
1/1
✓ Call 0 invoked.
12 vec3 yzx() const { return vec3(y, z, x); }
121
122 // Pre-increment and pre-decrement operators
123 12 vec3& operator++() {
124 12 ++x;
125 12 ++y;
126 12 ++z;
127 12 return *this;
128 }
129
130 12 vec3& operator--() {
131 12 --x;
132 12 --y;
133 12 --z;
134 12 return *this;
135 }
136
137 // Post-increment and post-decrement operators
138 vec3 operator++(int) {
139 vec3 tmp = *this;
140 ++*this;
141 return tmp;
142 }
143
144 vec3 operator--(int) {
145 vec3 tmp = *this;
146 --*this;
147 return tmp;
148 }
149
150 // Compound assignment operators
151 void operator+=(T a) {
152 x += a;
153 y += a;
154 z += a;
155 }
156
157 void operator+=(const vec3& v) {
158 x += v.x;
159 y += v.y;
160 z += v.z;
161 }
162
163 void operator-=(T a) {
164 x -= a;
165 y -= a;
166 z -= a;
167 }
168
169 void operator-=(const vec3& v) {
170 x -= v.x;
171 y -= v.y;
172 z -= v.z;
173 }
174
175 void operator*=(T a) {
176 x *= a;
177 y *= a;
178 z *= a;
179 }
180
181 void operator*=(const vec3& v) {
182 x *= v.x;
183 y *= v.y;
184 z *= v.z;
185 }
186
187 void operator/=(T a) {
188 x /= a;
189 y /= a;
190 z /= a;
191 }
192
193 void operator/=(const vec3& v) {
194 x /= v.x;
195 y /= v.y;
196 z /= v.z;
197 }
198
199 // Length of the vector
200
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
12 T length() const { return static_cast<T>(ez::sqrt(lengthSquared())); }
201
202 // Squared length of the vector
203 12 T lengthSquared() const { return x * x + y * y + z * z; }
204
205 // Normalize the vector
206 4 T normalize() {
207
1/1
✓ Call 0 invoked.
4 T _length = length();
208
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
4 if (_length < std::numeric_limits<T>::epsilon())
209 return static_cast<T>(0);
210 4 T _invLength = static_cast<T>(1) / _length;
211 4 x *= _invLength;
212 4 y *= _invLength;
213 4 z *= _invLength;
214 4 return _length;
215 }
216
217 // Get a normalized copy of the vector
218 vec3 GetNormalized() const {
219 vec3 n(x, y, z);
220 n.normalize();
221 return n;
222 }
223
224 // Sum of components
225 12 T sum() const { return x + y + z; }
226
227 // Sum of absolute values of components
228
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
8 T sumAbs() const { return ez::abs(x) + ez::abs(y) + ez::abs(z); }
229
230 // Check if all components are zero (AND)
231
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
24 bool emptyAND() const { return x == static_cast<T>(0) && y == static_cast<T>(0) && z == static_cast<T>(0); }
232
233 // Check if any component is zero (OR)
234
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
24 bool emptyOR() const { return x == static_cast<T>(0) || y == static_cast<T>(0) || z == static_cast<T>(0); }
235
236 // Convert to string
237
7/7
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 7 taken 6 times.
✓ Branch 10 taken 6 times.
✓ Branch 13 taken 6 times.
✓ Branch 16 taken 6 times.
✓ Branch 19 taken 6 times.
13/19
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✓ Call 21 invoked.
✓ Call 22 invoked.
✓ Call 23 invoked.
✓ Call 24 invoked.
✓ Call 25 invoked.
✓ Call 26 invoked.
✗ Call 27 not invoked.
✗ Call 28 not invoked.
✗ Call 29 not invoked.
✗ Call 30 not invoked.
✗ Call 31 not invoked.
✗ Call 32 not invoked.
12 std::string string(char c = ';') const { return ez::str::toStr(x) + c + ez::str::toStr(y) + c + ez::str::toStr(z); }
238
239 // Minimum component
240
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
12 T mini() const { return ez::mini(x, ez::mini(y, z)); }
241
242 // Maximum component
243
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
12 T maxi() const { return ez::maxi(x, ez::maxi(y, z)); }
244 };
245
246 // Operators for vec3
247 template <typename T>
248 inline vec3<T> operator+(const vec3<T>& v, T f) {
249 return vec3<T>(v.x + f, v.y + f, v.z + f);
250 }
251
252 template <typename T>
253 inline vec3<T> operator+(T f, const vec3<T>& v) {
254 return vec3<T>(v.x + f, v.y + f, v.z + f);
255 }
256
257 template <typename T>
258 32 inline vec3<T> operator+(const vec3<T>& v, const vec3<T>& f) {
259
1/1
✓ Call 0 invoked.
32 return vec3<T>(v.x + f.x, v.y + f.y, v.z + f.z);
260 }
261
262 template <typename T>
263 inline vec3<T> operator-(const vec3<T>& v, T f) {
264 return vec3<T>(v.x - f, v.y - f, v.z - f);
265 }
266
267 template <typename T>
268 inline vec3<T> operator-(T f, const vec3<T>& v) {
269 return vec3<T>(f - v.x, f - v.y, f - v.z);
270 }
271
272 template <typename T>
273 33 inline vec3<T> operator-(const vec3<T>& v, const vec3<T>& f) {
274
1/1
✓ Call 0 invoked.
33 return vec3<T>(v.x - f.x, v.y - f.y, v.z - f.z);
275 }
276
277 template <typename T>
278 12 inline vec3<T> operator*(const vec3<T>& v, T f) {
279
1/1
✓ Call 0 invoked.
12 return vec3<T>(v.x * f, v.y * f, v.z * f);
280 }
281
282 template <typename T>
283 inline vec3<T> operator*(T f, const vec3<T>& v) {
284 return vec3<T>(v.x * f, v.y * f, v.z * f);
285 }
286
287 template <typename T>
288 inline vec3<T> operator*(const vec3<T>& v, const vec3<T>& f) {
289 return vec3<T>(v.x * f.x, v.y * f.y, v.z * f.z);
290 }
291
292 template <typename T>
293 32 inline vec3<T> operator/(const vec3<T>& v, T f) {
294
1/1
✓ Call 0 invoked.
32 return vec3<T>(v.x / f, v.y / f, v.z / f);
295 }
296
297 template <typename T>
298 inline vec3<T> operator/(T f, const vec3<T>& v) {
299 return vec3<T>(f / v.x, f / v.y, f / v.z);
300 }
301
302 template <typename T>
303 inline vec3<T> operator/(const vec3<T>& v, const vec3<T>& f) {
304 return vec3<T>(v.x / f.x, v.y / f.y, v.z / f.z);
305 }
306
307 // Comparison operators
308 template <typename T>
309 inline bool operator<(const vec3<T>& v, const vec3<T>& f) {
310 return v.x < f.x && v.y < f.y && v.z < f.z;
311 }
312
313 template <typename T>
314 inline bool operator<(const vec3<T>& v, T f) {
315 return v.x < f && v.y < f && v.z < f;
316 }
317
318 template <typename T>
319 inline bool operator<(T f, const vec3<T>& v) {
320 return f < v.x && f < v.y && f < v.z;
321 }
322
323 template <typename T>
324 inline bool operator>(const vec3<T>& v, const vec3<T>& f) {
325 return v.x > f.x && v.y > f.y && v.z > f.z;
326 }
327
328 template <typename T>
329 inline bool operator>(const vec3<T>& v, T f) {
330 return v.x > f && v.y > f && v.z > f;
331 }
332
333 template <typename T>
334 inline bool operator>(T f, const vec3<T>& v) {
335 return f > v.x && f > v.y && f > v.z;
336 }
337
338 template <typename T>
339 inline bool operator<=(const vec3<T>& v, const vec3<T>& f) {
340 return v.x <= f.x && v.y <= f.y && v.z <= f.z;
341 }
342
343 template <typename T>
344 inline bool operator<=(const vec3<T>& v, T f) {
345 return v.x <= f && v.y <= f && v.z <= f;
346 }
347
348 template <typename T>
349 inline bool operator<=(T f, const vec3<T>& v) {
350 return f <= v.x && f <= v.y && f <= v.z;
351 }
352
353 template <typename T>
354 inline bool operator>=(const vec3<T>& v, const vec3<T>& f) {
355 return v.x >= f.x && v.y >= f.y && v.z >= f.z;
356 }
357
358 template <typename T>
359 inline bool operator>=(const vec3<T>& v, T f) {
360 return v.x >= f && v.y >= f && v.z >= f;
361 }
362
363 template <typename T>
364 inline bool operator>=(T f, const vec3<T>& v) {
365 return f >= v.x && f >= v.y && f >= v.z;
366 }
367
368 template <typename T>
369 inline bool operator!=(const vec3<T>& v, const vec3<T>& f) {
370 return v.x != f.x || v.y != f.y || v.z != f.z;
371 }
372
373 template <>
374 inline bool operator!=(const vec3<float>& v, const vec3<float>& f) {
375 return ez::isDifferent(v.x, f.x) || ez::isDifferent(v.y, f.y) || ez::isDifferent(v.z, f.z);
376 }
377
378 template <>
379 inline bool operator!=(const vec3<double>& v, const vec3<double>& f) {
380 return ez::isDifferent(v.x, f.x) || ez::isDifferent(v.y, f.y) || ez::isDifferent(v.z, f.z);
381 }
382
383 template <typename T>
384 inline bool operator!=(const vec3<T>& v, T f) {
385 return v.x != f || v.y != f || v.z != f;
386 }
387
388 template <typename T>
389 inline bool operator!=(T f, const vec3<T>& v) {
390 return f != v.x || f != v.y || f != v.z;
391 }
392
393 template <typename T>
394 16 inline bool operator==(const vec3<T>& v, const vec3<T>& f) {
395
4/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
16 return v.x == f.x && v.y == f.y && v.z == f.z;
396 }
397
398 template <>
399 2 inline bool operator==(const vec3<float>& v, const vec3<float>& f) {
400
4/6
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
2 return ez::isEqual(v.x, f.x) && ez::isEqual(v.y, f.y) && ez::isEqual(v.z, f.z);
401 }
402
403 template <>
404 2 inline bool operator==(const vec3<double>& v, const vec3<double>& f) {
405
4/6
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
2 return ez::isEqual(v.x, f.x) && ez::isEqual(v.y, f.y) && ez::isEqual(v.z, f.z);
406 }
407
408 template <typename T>
409 inline bool operator==(const vec3<T>& v, T f) {
410 return v.x == f && v.y == f && v.z == f;
411 }
412
413 template <typename T>
414 inline bool operator==(T f, const vec3<T>& v) {
415 return f == v.x && f == v.y && f == v.z;
416 }
417
418 // Utility functions
419 template <typename T>
420 inline vec3<T> mini(const vec3<T>& a, const vec3<T>& b) {
421 return vec3<T>(ez::mini(a.x, b.x), ez::mini(a.y, b.y), ez::mini(a.z, b.z));
422 }
423
424 template <typename T>
425 inline vec3<T> maxi(const vec3<T>& a, const vec3<T>& b) {
426 return vec3<T>(ez::maxi(a.x, b.x), ez::maxi(a.y, b.y), ez::maxi(a.z, b.z));
427 }
428
429 template <typename T>
430 inline vec3<T> floor(const vec3<T>& a) {
431 return vec3<T>(ez::floor(a.x), ez::floor(a.y), ez::floor(a.z));
432 }
433
434 template <typename T>
435 inline vec3<T> ceil(const vec3<T>& a) {
436 return vec3<T>(ez::ceil(a.x), ez::ceil(a.y), ez::ceil(a.z));
437 }
438
439 template <typename T>
440 inline vec3<T> abs(const vec3<T>& a) {
441 return vec3<T>(ez::abs(a.x), ez::abs(a.y), ez::abs(a.z));
442 }
443
444 template <typename T>
445 inline T dotS(const vec3<T>& a, const vec3<T>& b) {
446 return a.x * b.x + a.y * b.y + a.z * b.z;
447 }
448
449 template <typename T>
450 inline vec3<T> cCross(const vec3<T>& a, const vec3<T>& b) {
451 return vec3<T>(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
452 }
453
454 template <typename T>
455 inline vec3<T> cReflect(const vec3<T>& I, const vec3<T>& N) {
456 return I - static_cast<T>(2) * dotS(N, I) * N;
457 }
458
459 // Clamps a value between 0 and 1.
460 // Works with both integral and floating-point types.
461 template <typename T>
462 inline vec3<T> clamp(vec3<T> n) {
463 vec3<T> ret;
464 ret.x = ez::clamp(n.x);
465 ret.y = ez::clamp(n.y);
466 ret.z = ez::clamp(n.z);
467 return ret;
468 }
469
470 // Clamps a value between 0 and b.
471 // Works with both integral and floating-point types.
472 template <typename T>
473 inline vec3<T> clamp(vec3<T> n, T b) {
474 vec3<T> ret;
475 ret.x = ez::clamp(n.x, b);
476 ret.y = ez::clamp(n.y, b);
477 ret.z = ez::clamp(n.z, b);
478 return ret;
479 }
480
481 // Clamps a value between a and b.
482 // Works with both integral and floating-point types.
483 template <typename T>
484 inline vec3<T> clamp(vec3<T> n, T a, T b) {
485 vec3<T> ret;
486 ret.x = ez::clamp(n.x, a, b);
487 ret.y = ez::clamp(n.y, a, b);
488 ret.z = ez::clamp(n.z, a, b);
489 return ret;
490 }
491
492 // Type aliases for common vector types
493 using dvec3 = vec3<double>;
494 using fvec3 = vec3<float>;
495 using f32vec3 = vec3<float>;
496 using f64vec3 = vec3<double>;
497 using ivec3 = vec3<int>;
498 using i8vec3 = vec3<int8_t>;
499 using i16vec3 = vec3<int16_t>;
500 using i32vec3 = vec3<int32_t>;
501 using i64vec3 = vec3<int64_t>;
502 using u8vec3 = vec3<uint8_t>;
503 using u16vec3 = vec3<uint16_t>;
504 using uvec3 = vec3<uint32_t>;
505 using u32vec3 = vec3<uint32_t>;
506 using u64vec3 = vec3<uint64_t>;
507
508 // Specialization for float32 validation
509 inline bool valid(const fvec3& a) {
510 return floatIsValid(a.x) && floatIsValid(a.y) && floatIsValid(a.z);
511 }
512
513 template <typename T>
514 inline std::istream& operator>>(std::istream& vIn, vec3<T>& vType) {
515 char separator;
516 if (vIn >> vType.x >> separator >> vType.y >> separator >> vType.z) {
517 if (separator != ';') {
518 vIn.setstate(std::ios::failbit);
519 }
520 }
521 return vIn;
522 }
523
524 template <typename T>
525 inline std::ostream& operator<<(std::ostream& vOut, const vec3<T>& vType) {
526 vOut << vType.x << ";" << vType.y << ";" << vType.z;
527 return vOut;
528 }
529
530 } // namespace ez
531

Directory: include/ezlibs/
File: ezNamedPipe.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 51 58 87.9%
Functions: 12 12 100.0%
Branches: 23 33 69.7%
Decisions: 15 22 68.2%
Calls: 43 47 91.5%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezNamedPipes is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include "ezOS.hpp"
30
31 #include <vector>
32 #include <string>
33 #include <cstdint>
34 #include <memory>
35 #include <stdexcept>
36 #include <iostream>
37
38 #ifdef WINDOWS_OS
39 #include <Windows.h>
40 #else
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <dirent.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <cstring>
47 #endif
48
49 namespace ez {
50
51 class NamedPipe {
52 public:
53 typedef std::vector<char> DatasBuffer;
54
55 public:
56 static std::vector<std::string> getActivePipes() {
57 std::vector<std::string> pipeNames;
58 #ifdef WINDOWS_OS
59 char buffer[4096];
60
61 // Buffer pour les résultats
62 WIN32_FIND_DATAA findFileData;
63 HANDLE hFind = FindFirstFileA("\\\\.\\pipe\\*", &findFileData);
64
65 if (hFind == INVALID_HANDLE_VALUE) {
66 std::cerr << "Failed to list named pipes. Error: " << GetLastError() << std::endl;
67 return pipeNames;
68 }
69
70 do {
71 pipeNames.push_back(findFileData.cFileName); // Ajoute le nom du pipe à la liste
72 } while (FindNextFileA(hFind, &findFileData)); // Continue à chercher
73
74 FindClose(hFind); // Ferme le handle de recherche
75 #else
76 const auto directory = std::string("/tmp");
77 DIR* dir = opendir(directory.c_str());
78 if (dir) {
79 struct dirent* entry;
80 struct stat fileStat{};
81 while ((entry = readdir(dir)) != nullptr) {
82 std::string fullPath = directory + "/" + entry->d_name;
83 if (stat(fullPath.c_str(), &fileStat) == -1) {
84 std::cerr << "Failed to stat file: " << fullPath << std::endl;
85 continue;
86 }
87 if (S_ISFIFO(fileStat.st_mode)) {
88 pipeNames.push_back(fullPath);
89 }
90 }
91 closedir(dir);
92 }
93 #endif
94 return pipeNames;
95 }
96
97 private:
98 class Backend {
99 private:
100 size_t m_lastMessageSize{0};
101 std::vector<char> m_buffer;
102 std::string m_pipeName;
103 bool m_isServer{};
104 #ifdef WINDOWS_OS
105 HANDLE m_pipeHandle = INVALID_HANDLE_VALUE;
106 #else
107 int32_t m_pipeFd = -1;
108 #endif
109
110 public:
111
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
4 virtual ~Backend() { unit(); }
112
113 6 void unit() {
114 #ifdef WINDOWS_OS
115 if (m_pipeHandle != INVALID_HANDLE_VALUE) {
116 CloseHandle(m_pipeHandle);
117 }
118 m_pipeHandle = INVALID_HANDLE_VALUE;
119 #else
120
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 4 times.
6 if (m_pipeFd != -1) {
121
1/1
✓ Call 0 invoked.
2 close(m_pipeFd);
122
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (m_isServer) {
123
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 unlink(m_pipeName.c_str());
124 }
125 }
126 6 m_pipeFd = -1;
127 #endif
128 6 }
129
130 3 bool writeBuffer(const DatasBuffer& vMessage) {
131 #ifdef WINDOWS_OS
132 DWORD bytesWritten;
133 if (!WriteFile(m_pipeHandle, vMessage.data(), vMessage.size(), &bytesWritten, nullptr)) {
134 return false;
135 }
136 #else
137
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
3 auto bytesWritten = ::write(m_pipeFd, vMessage.data(), vMessage.size());
138
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
3 if (bytesWritten == -1) {
139 1 return false;
140 }
141 #endif
142 2 return true;
143 }
144
145 3 bool writeString(const std::string& vMessage) {
146
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
3 if (!vMessage.empty()) {
147
1/1
✓ Branch 3 taken 3 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
3 const ez::NamedPipe::DatasBuffer buffer(vMessage.begin(), vMessage.end());
148
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 return writeBuffer(buffer);
149
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
3 }
150 return false;
151 }
152
153 2 bool isMessageReceived() {
154 #ifdef WINDOWS_OS
155 DWORD bytesRead;
156 if (ReadFile(m_pipeHandle, m_buffer.data(), m_buffer.size(), &bytesRead, nullptr) == TRUE) {
157 m_lastMessageSize = bytesRead;
158 return true;
159 }
160 return false;
161 #else
162
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
2 auto bytesRead = ::read(m_pipeFd, m_buffer.data(), m_buffer.size());
163
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (bytesRead != -1) {
164 1 m_lastMessageSize = bytesRead;
165 1 return true;
166 }
167 1 return false;
168 #endif
169 }
170
171 DatasBuffer readBuffer(size_t& vOutSize) {
172 vOutSize = m_lastMessageSize;
173 return m_buffer;
174 }
175
176 2 std::string readString() {
177
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
2 if (m_lastMessageSize) {
178
1/1
✓ Branch 2 taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
4 return std::string(m_buffer.data(), m_lastMessageSize);
179 }
180
0/1
✗ Call 0 not invoked.
return {};
181 }
182
183 protected:
184 1 bool m_initServer(const std::string& vPipeName, size_t vBufferSize, int32_t vMaxInstances = 1) {
185 1 m_isServer = true;
186
1/1
✓ Call 0 invoked.
1 m_buffer.resize(vBufferSize);
187 #ifdef WINDOWS_OS
188 m_pipeName = "\\\\.\\pipe\\" + vPipeName;
189 m_pipeHandle = CreateNamedPipe( //
190 m_pipeName.c_str(),
191 PIPE_ACCESS_DUPLEX,
192 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
193 vMaxInstances, // Max instances
194 vBufferSize, // Output buffer size
195 vBufferSize, // Input buffer size
196 0, // Default timeout
197 nullptr // Default security attributes
198 );
199 if (m_pipeHandle == INVALID_HANDLE_VALUE) {
200 return false;
201 }
202 #else
203
1/1
✓ Branch 1 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
1 m_pipeName = "/tmp/" + vPipeName;
204
2/6
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 if (mkfifo(m_pipeName.c_str(), 0666) == -1 && errno != EEXIST) {
205 return false;
206 }
207
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 m_pipeFd = open(m_pipeName.c_str(), O_RDWR);
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (m_pipeFd == -1) {
209 return false;
210 }
211 #endif
212 1 return true;
213 }
214
215 1 bool m_initClient(const std::string& vPipeName
216 #ifdef EZ_TIME
217 , size_t vTimeOutInMs = 1000u
218 #endif
219 ) {
220 1 m_isServer = false;
221 #ifdef WINDOWS_OS
222 m_pipeName = "\\\\.\\pipe\\" + vPipeName;
223 #ifdef EZ_TIME
224 const auto start = ez::time::getTicks();
225 #endif
226 #ifdef EZ_TIME
227 while (m_pipeHandle == INVALID_HANDLE_VALUE) {
228 #endif
229 m_pipeHandle = CreateFile( //
230 m_pipeName.c_str(),
231 GENERIC_READ | GENERIC_WRITE,
232 0,
233 nullptr,
234 OPEN_ALWAYS,
235 0,
236 nullptr);
237 #ifdef EZ_TIME
238 if (m_pipeHandle == INVALID_HANDLE_VALUE && //
239 (ez::time::getTicks() - start) > vTimeOutInMs) {
240 break;
241 }
242 }
243 #endif
244 if (m_pipeHandle == INVALID_HANDLE_VALUE) {
245 return false;
246 }
247 #else
248
1/1
✓ Branch 1 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
1 m_pipeName = "/tmp/" + vPipeName;
249
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 m_pipeFd = open(m_pipeName.c_str(), O_RDWR);
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (m_pipeFd == -1) {
251 return false;
252 }
253 #endif
254 1 return true;
255 }
256 };
257
258 public:
259 class Server : public Backend {
260 public:
261 typedef std::shared_ptr<Server> Ptr;
262 typedef std::weak_ptr<Server> Weak;
263
264 public:
265 1 static Ptr create(const std::string& pipeName, size_t vBufferSize, int32_t vMaxInstances = 1) {
266
1/1
✓ Call 0 invoked.
1 auto ret = std::make_shared<Server>();
267
2/3
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 if (!ret->m_initServer(pipeName, vBufferSize, vMaxInstances)) {
268
0/1
✗ Call 0 not invoked.
ret.reset();
269 }
270 1 return ret;
271 }
272
273
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 ~Server() override { unit(); }
274 };
275
276
277 class Client : public Backend {
278 public:
279 typedef std::shared_ptr<Client> Ptr;
280 typedef std::weak_ptr<Client> Weak;
281
282 public:
283 1 static Ptr create(const std::string& pipeName) {
284
1/1
✓ Call 0 invoked.
1 auto ret = std::make_shared<Client>();
285
2/3
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 if (!ret->m_initClient(pipeName)) {
286
0/1
✗ Call 0 not invoked.
ret.reset();
287 }
288 1 return ret;
289 }
290
291
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
2 ~Client() override { unit(); }
292 };
293 };
294
295 } // namespace ez
296

Directory: include/ezlibs/
File: ezCnt.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 13 14 92.9%
Functions: 6 6 100.0%
Branches: 4 5 80.0%
Decisions: 3 4 75.0%
Calls: 12 12 100.0%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezBmp is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <string>
30 #include <vector>
31 #include <unordered_map>
32
33 namespace ez {
34 namespace cnt {
35
36 // this class can be indexed like a vector
37 // and searched in like a dico
38 template <typename TKey, typename TValue = TKey>
39 class DicoVector {
40 protected:
41 std::unordered_map<TKey, size_t> m_dico;
42 std::vector<TValue> m_array;
43
44 public:
45 void clear() {
46 m_dico.clear();
47 m_array.clear();
48 }
49 bool empty() const { return m_array.empty(); }
50 size_t size() const { return m_array.size(); }
51 TValue& operator[](const size_t& vIdx) { return m_array[vIdx]; }
52 TValue& at(const size_t& vIdx) { return m_array.at(vIdx); }
53 const TValue& operator[](const size_t& vIdx) const { return m_array[vIdx]; }
54 const TValue& at(const size_t& vIdx) const { return m_array.at(vIdx); }
55 typename std::vector<TValue>::iterator begin() { return m_array.begin(); }
56 typename std::vector<TValue>::const_iterator begin() const { return m_array.begin(); }
57 typename std::vector<TValue>::iterator end() { return m_array.end(); }
58 typename std::vector<TValue>::const_iterator end() const { return m_array.end(); }
59
1/1
✓ Branch 2 taken 4 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
8 bool exist(const TKey& vKey) const { return (m_dico.find(vKey) != m_dico.end()); }
60 TValue& value(const TKey& vKey) { return at(m_dico.at(vKey)); }
61 const TValue& value(const TKey& vKey) const { return at(m_dico.at(vKey)); }
62 void resize(const size_t vNewSize) { m_array.resize(vNewSize); }
63 void resize(const size_t vNewSize, const TValue& vVal) { m_array.resize(vNewSize, vVal); }
64 void reserve(const size_t vNewCapacity) { m_array.reserve(vNewCapacity); }
65 bool erase(const TKey& vKey) {
66 if (exist(vKey)) {
67 // when we erase an entry, there is as issue
68 // in the vector because the indexs are not more corresponding
69 auto idx = m_dico.at(vKey);
70 for (auto& it : m_dico) {
71 // we must modify all index greater than the index to delete
72 if (it.second > idx) {
73 --it.second;
74 }
75 }
76 // now we can safely erase the item from both dico and vector
77 m_array.erase(m_array.begin() + idx);
78 m_dico.erase(vKey);
79 return true;
80 }
81 return false;
82 }
83
1/1
✓ Call 0 invoked.
1 bool tryAdd(const TKey& vKeyValue) { return tryAdd(vKeyValue, vKeyValue); }
84 6 bool tryAdd(const TKey& vKey, const TValue& vValue) {
85
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
1/1
✓ Call 0 invoked.
6 if (!exist(vKey)) {
86
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
4 m_dico[vKey] = m_array.size();
87
1/1
✓ Call 0 invoked.
4 m_array.push_back(vValue);
88 4 return true;
89 }
90 2 return false;
91 }
92 bool trySetExisting(const TKey& vKeyValue) { return trySetExisting(vKeyValue, vKeyValue); }
93 1 bool trySetExisting(const TKey& vKey, const TValue& vValue) {
94
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (exist(vKey)) {
95
1/1
✓ Call 0 invoked.
1 auto row = m_dico.at(vKey);
96
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 m_array[row] = vValue;
97 1 return true;
98 }
99 return false;
100 }
101 // the merge can be partialy done, if already key was existing
102 bool tryMerge(const DicoVector<TKey, TValue>& vDico) {
103 bool ret = false;
104 for (const auto& it : vDico.m_dico) {
105 ret |= tryAdd(it.first, vDico.at(it.second));
106 }
107 return ret;
108 }
109 };
110
111 } // namespace cnt
112 } // namespace ez
113

Directory: include/ezlibs/
File: ezCron.hpp
Date: 2025-07-28 14:06:36
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 267 280 95.4%
Functions: 25 25 100.0%
Branches: 234 254 92.1%
Decisions: 132 144 91.7%
Calls: 244 297 82.2%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezCron is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <set>
30 #include <ctime>
31 #include <array>
32 #include <string>
33 #include <vector>
34 #include <cstdint>
35 #include <sstream>
36 #include <iterator>
37 #include <iostream>
38
39 ////////////////////////////////////////////////////////////////////////////
40 ////////////////////////////////////////////////////////////////////////////
41 ////////////////////////////////////////////////////////////////////////////
42
43 #ifdef _MSC_VER
44 #pragma warning(push)
45 #pragma warning(disable : 4244) // Conversion from 'double' to 'float', possible loss of data
46 #pragma warning(disable : 4305) // Truncation from 'double' to 'float'
47 #elif defined(__GNUC__) || defined(__clang__)
48 #pragma GCC diagnostic push
49 #pragma GCC diagnostic ignored "-Wconversion"
50 #pragma GCC diagnostic ignored "-Wfloat-conversion"
51 #endif
52
53 ////////////////////////////////////////////////////////////////////////////
54 ////////////////////////////////////////////////////////////////////////////
55 ////////////////////////////////////////////////////////////////////////////
56
57 namespace ez {
58 namespace time {
59
60 // Supported Crontab format
61 // 'mm hh dd MM DD'
62 // mm : the minutes from 0 to 59
63 // hh : the hour from 0 to 23
64 // dd : the day of the month from 1 to 31
65 // MM : the month from 1 to 12
66 // DD : the day of the week from 0 to 7. 0 and 7 are the sunday
67 // For each fields, thoses forms are accepted :
68 // * : always valid units (0,1,3,4, etc..)
69 // 5,8 : the units 5 and 8
70 // 2-5 : the units from 2 to 5 (2, 3, 4, 5)
71 // */3 : all the 3 interval units(0, 3, 6, 9, etc..)
72
73 class Cron {
74 friend class TestCron;
75
76 public:
77 enum ErrorFlags { //
78 NONE = (0),
79 INVALID_MINUTE = (1 << 0),
80 INVALID_HOUR = (1 << 1),
81 INVALID_MONTH_DAY = (1 << 2),
82 INVALID_MONTH = (1 << 3),
83 INVALID_WEEK_DAY = (1 << 4),
84 INVALID_FIELDS_COUNT = (1 << 5),
85 INVALID_CHAR = (1 << 6),
86 INVALID_RANGE = (1 << 7),
87 INVALID_INTERVAL = (1 << 8),
88 INVALID_VALUES = (1 << 9),
89 INVALID_FIELD = (1 << 10)
90 };
91 enum class FieldType { //
92 VALUE = 0, // Value
93 INTERVAL, // Interval. each values
94 RANGE, // Range [min:max]
95 VALUES, // Values [v0,v1,v2]
96 WILDCARD, // Valid value for all
97 Count
98 };
99 enum class FieldIndex { //
100 MINUTE = 0,
101 HOUR,
102 DAY_MONTH,
103 MONTH,
104 DAY_WEEK,
105 Count
106 };
107 struct Field {
108 std::string str; // field str
109 FieldIndex index{FieldIndex::MINUTE}; // field index
110 int32_t cpos{-1}; // char pos in the cron rule
111 FieldType type{FieldType::VALUE}; // field type
112 int32_t value{-1}; // the value with type is 'value'
113 int32_t interval{-1}; // the interval value when type is 'interval'
114 std::pair<int32_t, int32_t> range{std::make_pair(-1, -1)}; // the range when type is 'range'
115 std::set<int32_t> values{}; // the valude when type is 'values'
116 };
117 struct ErrorDetail {
118 int32_t flag{};
119 int32_t position{-1};
120 std::string message;
121 };
122
123 private:
124 int32_t m_errorFlags;
125 std::string m_cronRule;
126 std::vector<Field> m_fields;
127 std::vector<ErrorDetail> m_errorDetails;
128
129 public:
130 39 Cron(const std::string& m_cronRule) //
131
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
39 : m_errorFlags(NONE), m_cronRule(m_cronRule) {
132
1/1
✓ Branch 1 taken 39 times.
1/1
✓ Call 0 invoked.
39 m_parseExpression();
133
0/3
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
39 }
134
135 73 bool isOk() const {
136 73 return (m_errorFlags == NONE);
137 }
138
139 2 const std::string& getCronRule() const {
140 2 return m_cronRule;
141 }
142
143 28 int getErrorFlags() const {
144 28 return m_errorFlags;
145 }
146
147 1 const std::vector<Field>& getFields() const {
148 1 return m_fields;
149 }
150
151 4 bool isTimeToAct() const {
152
1/1
✓ Call 0 invoked.
4 time_t currentTime = std::time(nullptr);
153
1/1
✓ Call 0 invoked.
4 return isTimeToAct(currentTime);
154 }
155
156 34 bool isTimeToAct(time_t vCurrentTime) const {
157
1/2
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 34 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
34 if (isOk()) {
158 #ifdef _MSC_VER
159 struct tm _tm;
160 localtime_s(&_tm, &vCurrentTime);
161 auto* currentTm = &_tm;
162 #else
163
1/1
✓ Call 0 invoked.
34 auto* currentTm = std::localtime(&vCurrentTime);
164 #endif
165 return //
166
1/1
✓ Call 0 invoked.
34 m_checkTimeForField(FieldIndex::MINUTE, currentTm->tm_min) && //
167
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
14 m_checkTimeForField(FieldIndex::HOUR, currentTm->tm_hour) && //
168
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
14 m_checkTimeForField(FieldIndex::DAY_MONTH, currentTm->tm_mday) && //
169
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 20 times.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
1/1
✓ Call 2 invoked.
62 m_checkTimeForField(FieldIndex::MONTH, currentTm->tm_mon + 1) && //
170
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
1/1
✓ Call 0 invoked.
48 m_checkTimeForField(FieldIndex::DAY_WEEK, currentTm->tm_wday);
171 }
172 return false;
173 }
174
175 39 std::string getErrorMessage() const {
176
1/1
✓ Branch 1 taken 39 times.
1/1
✓ Call 0 invoked.
39 std::stringstream err;
177
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 28 times.
2/2
✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 28 times.
1/1
✓ Call 0 invoked.
39 if (m_errorDetails.empty()) {
178
1/1
✓ Branch 1 taken 11 times.
1/1
✓ Call 0 invoked.
11 std::cout << "No errors found.\n";
179 } else {
180
2/2
✓ Branch 1 taken 28 times.
✓ Branch 4 taken 28 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
28 err << "Errors found in cron rule : " << std::endl;
181
2/2
✓ Branch 1 taken 28 times.
✓ Branch 4 taken 28 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
28 err << m_cronRule << std::endl;
182
3/3
✓ Branch 4 taken 106 times.
✓ Branch 6 taken 78 times.
✓ Branch 7 taken 28 times.
0/1
? Decision couldn't be analyzed.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
106 for (auto rev_it = m_errorDetails.rbegin(); rev_it != m_errorDetails.rend(); ++rev_it) {
183
3/3
✓ Branch 1 taken 78 times.
✓ Branch 3 taken 61 times.
✓ Branch 4 taken 17 times.
2/2
✓ Decision 'true' taken 61 times.
✓ Decision 'false' taken 17 times.
1/1
✓ Call 0 invoked.
78 if (rev_it->position >= 0) {
184
1/1
✓ Branch 2 taken 61 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
61 std::string marker_line(m_cronRule.size(), ' ');
185
2/2
✓ Branch 4 taken 248 times.
✓ Branch 5 taken 61 times.
2/2
✓ Decision 'true' taken 248 times.
✓ Decision 'false' taken 61 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
309 for (auto it = m_errorDetails.begin(); it != m_errorDetails.end(); ++it) {
186
2/2
✓ Branch 1 taken 231 times.
✓ Branch 2 taken 17 times.
2/2
✓ Decision 'true' taken 231 times.
✓ Decision 'false' taken 17 times.
1/1
✓ Call 0 invoked.
248 if (it->position >= 0) {
187
1/1
✓ Branch 2 taken 231 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
231 marker_line[it->position] = '|';
188 }
189 }
190
2/2
✓ Branch 1 taken 61 times.
✓ Branch 4 taken 61 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
61 marker_line[rev_it->position] = '^';
191
2/2
✓ Branch 1 taken 61 times.
✓ Branch 4 taken 61 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
61 marker_line = marker_line.substr(0, rev_it->position + 1);
192
9/9
✓ Branch 1 taken 61 times.
✓ Branch 4 taken 61 times.
✓ Branch 7 taken 61 times.
✓ Branch 10 taken 61 times.
✓ Branch 13 taken 61 times.
✓ Branch 16 taken 61 times.
✓ Branch 19 taken 61 times.
✓ Branch 22 taken 61 times.
✓ Branch 25 taken 61 times.
10/11
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✓ Call 21 invoked.
✓ Call 24 invoked.
✓ Call 27 invoked.
✗ Call 28 not invoked.
61 err << marker_line << "--<| " << m_getErrorString(rev_it->flag) << " " << rev_it->message << std::endl;
193
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
61 }
194 }
195 }
196
1/1
✓ Branch 1 taken 39 times.
1/1
✓ Call 0 invoked.
78 return err.str();
197
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
39 }
198
199 std::string getSupportedFormat() const {
200 return u8R"(
201 Supported Crontab format
202 mm hh dd MM DD
203 mm : the minutes from 0 to 59
204 hh : the hour from 0 to 23
205 dd : the day of the month from 1 to 31
206 MM : the month from 1 to 12
207 DD : the day of the week from 0 to 7. 0 and 7 are the sunday
208 For each fields, thoses forms are accepted :
209 * : always valid units (0,1,3,4, etc..)
210 5,8 : the units 5 and 8
211 2-5 : the units from 2 to 5 (2, 3, 4, 5)
212 */3 : all the 3 interval units (0, 3, 6, 9, etc..)
213 )";
214 }
215
216 private:
217 typedef int32_t CharPos;
218 typedef std::pair<CharPos, std::string> Token;
219 160 std::vector<Token> m_split(const std::string& vText, const std::string& vDelimiters) {
220
1/1
✓ Call 0 invoked.
160 std::vector<Token> arr;
221
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 160 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
160 if (!vText.empty()) {
222 160 size_t start = 0;
223
1/1
✓ Call 0 invoked.
160 std::string token;
224
1/1
✓ Call 0 invoked.
160 auto end = vText.find_first_of(vDelimiters, start);
225
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 111 times.
2/2
✓ Decision 'true' taken 49 times.
✓ Decision 'false' taken 111 times.
160 if (end != std::string::npos) {
226
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 49 times.
2/2
✓ Decision 'true' taken 172 times.
✓ Decision 'false' taken 49 times.
221 while (end != std::string::npos) {
227
1/1
✓ Branch 1 taken 172 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
172 token = vText.substr(start, end - start);
228
2/2
✓ Branch 1 taken 172 times.
✓ Branch 4 taken 172 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
172 arr.push_back(std::make_pair(static_cast<CharPos>(start), token)); // empty token or not
229 172 start = end + 1;
230
1/1
✓ Call 0 invoked.
172 end = vText.find_first_of(vDelimiters, start);
231 }
232
1/1
✓ Branch 1 taken 49 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
49 token = vText.substr(start);
233
2/2
✓ Branch 1 taken 49 times.
✓ Branch 4 taken 49 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
49 arr.push_back(std::make_pair(static_cast<CharPos>(start), token)); // empty token or not
234 }
235
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
160 }
236 160 return arr;
237 }
238
239 61 int32_t m_getErrorFlagFromIndex(FieldIndex vIndex) {
240 61 return (1 << static_cast<int32_t>(vIndex));
241 }
242
243 template <typename U, typename V, typename W>
244 198 void m_addError(U vFlag, V vCharPos, W vIndex, const std::string& vMessage = {}) {
245 198 auto idx = static_cast<size_t>(vIndex);
246
2/2
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 99 times.
2/2
✓ Decision 'true' taken 78 times.
✓ Decision 'false' taken 99 times.
1/1
✓ Call 0 invoked.
354 while (m_errorDetails.size() <= idx) {
247
1/1
✓ Branch 2 taken 78 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
156 m_errorDetails.push_back({});
248 }
249
1/1
✓ Call 0 invoked.
198 auto& ed = m_errorDetails.at(idx);
250 198 ed.flag |= static_cast<int32_t>(vFlag);
251 198 auto cp = static_cast<int32_t>(vCharPos);
252
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 38 times.
2/2
✓ Decision 'true' taken 61 times.
✓ Decision 'false' taken 38 times.
198 if (ed.position < 0) {
253 122 ed.position = cp;
254
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 26 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 26 times.
76 } else if (cp > ed.position) {
255 24 ed.position = cp;
256 }
257
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 97 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 97 times.
1/1
✓ Call 0 invoked.
198 if (!vMessage.empty()) {
258
1/1
✓ Call 0 invoked.
4 ed.message += vMessage;
259 }
260 198 m_errorFlags |= ed.flag;
261 198 }
262
263 5 bool m_fieldHaveError(Field& vInOutField) {
264 5 auto idx = static_cast<size_t>(vInOutField.index);
265
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
5 if (m_errorDetails.size() > idx) {
266
1/1
✓ Call 0 invoked.
1 return (m_errorDetails.at(idx).position > 0);
267 }
268 4 return false;
269 }
270
271 113 bool m_parseValue(Field& vInOutField, const std::string& vValue, int32_t vCharPos) {
272 try {
273
1/1
✓ Call 0 invoked.
113 auto wpos = vInOutField.str.find_first_not_of("0123456789/*-,");
274
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 103 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 103 times.
113 if (wpos != std::string::npos) {
275
1/1
✓ Branch 3 taken 10 times.
4/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
✗ Call 6 not invoked.
10 m_addError(INVALID_CHAR | m_getErrorFlagFromIndex(vInOutField.index), vInOutField.cpos + wpos, vInOutField.index);
276 25 return false;
277 }
278
1/1
✓ Branch 1 taken 73 times.
1/1
✓ Call 0 invoked.
103 auto v = std::stoi(vValue);
279 // check min/max
280
6/6
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 1 times.
73 switch (vInOutField.index) {
281
1/1
✓ Decision 'true' taken 30 times.
30 case FieldIndex::MINUTE: {
282
3/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 27 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 27 times.
30 if (v < 0 || v > 59) {
283
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_addError(ErrorFlags::INVALID_MINUTE, vCharPos, vInOutField.index);
284 3 return false;
285 }
286 27 } break;
287
1/1
✓ Decision 'true' taken 13 times.
13 case FieldIndex::HOUR: {
288
3/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 10 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 10 times.
13 if (v < 0 || v > 23) {
289
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_addError(ErrorFlags::INVALID_HOUR, vCharPos, vInOutField.index);
290 3 return false;
291 }
292 10 } break;
293
1/1
✓ Decision 'true' taken 9 times.
9 case FieldIndex::DAY_MONTH: {
294
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 6 times.
9 if (v < 1 || v > 31) {
295
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_addError(ErrorFlags::INVALID_MONTH_DAY, vCharPos, vInOutField.index);
296 3 return false;
297 }
298 6 } break;
299
1/1
✓ Decision 'true' taken 8 times.
8 case FieldIndex::MONTH: {
300
3/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 5 times.
8 if (v < 1 || v > 12) {
301
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_addError(ErrorFlags::INVALID_MONTH, vCharPos, vInOutField.index);
302 3 return false;
303 }
304 5 } break;
305
1/1
✓ Decision 'true' taken 12 times.
12 case FieldIndex::DAY_WEEK: {
306
3/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 9 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 9 times.
12 if (v < 0 || v > 7) {
307
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_addError(ErrorFlags::INVALID_WEEK_DAY, vCharPos, vInOutField.index);
308 3 return false;
309 }
310 9 } break;
311
1/1
✓ Decision 'true' taken 1 times.
1 case FieldIndex::Count:
312
1/1
✓ Decision 'true' taken 1 times.
1 default: break;
313 }
314 // set value
315
4/5
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
58 switch (vInOutField.type) {
316
1/1
✓ Decision 'true' taken 22 times.
22 case FieldType::VALUE: {
317 22 vInOutField.value = v;
318 22 } break;
319
1/1
✓ Decision 'true' taken 21 times.
21 case FieldType::INTERVAL: {
320 21 vInOutField.interval = v;
321 21 } break;
322
1/1
✓ Decision 'true' taken 8 times.
8 case FieldType::RANGE: {
323
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 4 times.
8 if (vInOutField.range.first == -1) {
324 4 vInOutField.range.first = v;
325 } else {
326 4 vInOutField.range.second = v;
327 }
328 8 } break;
329
1/1
✓ Decision 'true' taken 7 times.
7 case FieldType::VALUES: {
330
1/1
✓ Branch 1 taken 7 times.
1/1
✓ Call 0 invoked.
7 vInOutField.values.emplace(v);
331 7 } break;
332
0/1
✗ Decision 'true' not taken.
case FieldType::WILDCARD:
333 case FieldType::Count:
334
0/1
✗ Decision 'true' not taken.
default: break;
335 }
336
1/1
✓ Call 0 invoked.
30 } catch (...) {
337
1/1
✓ Branch 3 taken 30 times.
4/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
✗ Call 6 not invoked.
30 m_addError(m_getErrorFlagFromIndex(vInOutField.index), vCharPos, vInOutField.index);
338 30 return false;
339
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
30 }
340 58 return true;
341 }
342
343 77 bool m_parseValue(Field& vInOutField, const Token& vToken) {
344
1/1
✓ Call 0 invoked.
77 return m_parseValue(vInOutField, vToken.second, vToken.first);
345 }
346
347 195 bool m_isInterval(Field& vInOutField) {
348
1/2
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 195 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
195 if (!vInOutField.str.empty()) {
349
1/1
✓ Call 0 invoked.
195 auto wpos = vInOutField.str.find("*");
350
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 59 times.
2/2
✓ Decision 'true' taken 136 times.
✓ Decision 'false' taken 59 times.
195 if (wpos != std::string::npos) {
351
1/1
✓ Call 0 invoked.
136 auto bad_pos = vInOutField.str.find_first_not_of("0123456789/*");
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 136 times.
136 if (bad_pos != std::string::npos) {
353
0/5
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
m_addError(INVALID_INTERVAL | m_getErrorFlagFromIndex(vInOutField.index), //
354
0/1
✗ Call 0 not invoked.
vInOutField.cpos + bad_pos,
355 vInOutField.index);
356 return true; // we not want to continue the field check
357 }
358
2/2
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 90 times.
2/2
✓ Decision 'true' taken 46 times.
✓ Decision 'false' taken 90 times.
1/1
✓ Call 0 invoked.
136 if (wpos < (vInOutField.str.size() - 1)) { // interval pattern '*/'
359 46 ++wpos;
360
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 10 times.
2/2
✓ Decision 'true' taken 36 times.
✓ Decision 'false' taken 10 times.
1/1
✓ Call 0 invoked.
46 if (vInOutField.str[wpos] == '/') {
361 36 ++wpos;
362
1/1
✓ Branch 1 taken 36 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
36 vInOutField.str = vInOutField.str.substr(wpos);
363 36 vInOutField.type = FieldType::INTERVAL;
364
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 21 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 21 times.
1/1
✓ Call 0 invoked.
36 if (!m_parseValue(vInOutField, vInOutField.str, static_cast<int32_t>(wpos))) {
365
1/1
✓ Branch 2 taken 15 times.
3/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
15 m_addError(INVALID_INTERVAL, vInOutField.cpos + wpos, vInOutField.index);
366 15 return false; // wildcard, stop field checking
367 }
368 } else {
369
1/1
✓ Branch 2 taken 10 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
20 m_addError(INVALID_INTERVAL | m_getErrorFlagFromIndex(vInOutField.index), //
370
1/1
✓ Call 0 invoked.
10 vInOutField.cpos + wpos,
371 vInOutField.index);
372 }
373 } else { // generic pattern '*'
374 90 vInOutField.type = FieldType::WILDCARD;
375 }
376 121 return true; // wildcard, stop field checking
377 }
378 }
379 59 return false; // no wildcard, continue field checking
380 }
381
382 74 bool m_isRange(Field& vInOutField) {
383
2/2
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 69 times.
✓ Decision 'false' taken 5 times.
1/1
✓ Call 0 invoked.
74 if (!vInOutField.str.empty()) {
384
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 67 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 67 times.
1/1
✓ Call 0 invoked.
69 if (vInOutField.str.front() == '-') {
385
1/1
✓ Branch 3 taken 2 times.
4/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
✗ Call 6 not invoked.
2 m_addError(INVALID_RANGE | m_getErrorFlagFromIndex(vInOutField.index), //
386 vInOutField.cpos,
387 vInOutField.index);
388 10 return true; // range, stop field checking
389
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 66 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 66 times.
1/1
✓ Call 0 invoked.
67 } else if (vInOutField.str.back() == '-') {
390
1/1
✓ Branch 2 taken 1 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
2 m_addError(INVALID_RANGE | m_getErrorFlagFromIndex(vInOutField.index), //
391
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 vInOutField.cpos + vInOutField.str.size() - 1,
392 vInOutField.index);
393 1 return true; // range, stop field checking
394 }
395
2/2
✓ Branch 1 taken 66 times.
✓ Branch 4 taken 66 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
66 auto tokens = m_split(vInOutField.str, "-");
396
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 59 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 59 times.
1/1
✓ Call 0 invoked.
66 if (!tokens.empty()) {
397 7 vInOutField.type = FieldType::RANGE;
398
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 5 times.
1/1
✓ Call 0 invoked.
7 if (tokens.size() != 2) {
399
1/1
✓ Call 0 invoked.
2 auto err_pos = vInOutField.str.size();
400
2/2
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
6 for (const auto& token : tokens) {
401
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
5 if (token.second.empty()) {
402 1 err_pos = token.first;
403 1 break;
404 }
405 }
406
1/1
✓ Branch 2 taken 2 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
4 m_addError(INVALID_RANGE | m_getErrorFlagFromIndex(vInOutField.index), //
407
1/1
✓ Call 0 invoked.
2 vInOutField.cpos + err_pos,
408 vInOutField.index);
409 2 return true; // range, stop field checking
410 }
411
2/2
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 5 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 5 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
15 for (const auto& token : tokens) {
412
3/3
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 8 times.
1/1
✓ Call 0 invoked.
10 if (!m_parseValue(vInOutField, token)) {
413
1/1
✓ Branch 2 taken 2 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
2 m_addError(INVALID_RANGE, vInOutField.cpos + token.first, vInOutField.index);
414 }
415 }
416
3/3
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 1 times.
1/1
✓ Call 0 invoked.
5 if (!m_fieldHaveError(vInOutField)) {
417
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3 times.
4 if (vInOutField.range.first == vInOutField.range.second) { // 5-5
418
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
3 m_addError(INVALID_RANGE | m_getErrorFlagFromIndex(vInOutField.index), //
419
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 vInOutField.cpos + tokens[1].first,
420 vInOutField.index,
421 " End must be different than Start.");
422
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
3 } else if (vInOutField.range.first > vInOutField.range.second) { // 5-4
423
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
3 m_addError(INVALID_RANGE | m_getErrorFlagFromIndex(vInOutField.index), //
424
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 vInOutField.cpos + tokens[1].first,
425 vInOutField.index,
426 " End must be greater than Start.");
427 }
428 }
429 5 return true; // range, stop field checking
430 }
431
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
66 }
432 64 return false; // no range, continue field checking
433 }
434
435 64 bool m_isValues(Field& vInOutField) {
436
2/2
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 59 times.
✓ Decision 'false' taken 5 times.
1/1
✓ Call 0 invoked.
64 if (!vInOutField.str.empty()) {
437
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 56 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 56 times.
1/1
✓ Call 0 invoked.
59 if (vInOutField.str.front() == ',') {
438
1/1
✓ Branch 3 taken 3 times.
4/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 5 invoked.
✗ Call 6 not invoked.
3 m_addError(INVALID_VALUES | m_getErrorFlagFromIndex(vInOutField.index), //
439 vInOutField.cpos,
440 vInOutField.index);
441 7 return true; // range, stop field checking
442
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 55 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 55 times.
1/1
✓ Call 0 invoked.
56 } else if (vInOutField.str.back() == ',') {
443
1/1
✓ Branch 2 taken 1 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
2 m_addError(INVALID_VALUES | m_getErrorFlagFromIndex(vInOutField.index), //
444
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 vInOutField.cpos + vInOutField.str.size() - 1,
445 vInOutField.index);
446 1 return true; // range, stop field checking
447 }
448
2/2
✓ Branch 1 taken 55 times.
✓ Branch 4 taken 55 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
55 auto tokens = m_split(vInOutField.str, ",");
449
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 52 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 52 times.
1/1
✓ Call 0 invoked.
55 if (!tokens.empty()) {
450 3 vInOutField.type = FieldType::VALUES;
451
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
3 if (tokens.size() == 1) {
452
0/5
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
m_addError(INVALID_VALUES | m_getErrorFlagFromIndex(vInOutField.index), //
453
0/1
✗ Call 0 not invoked.
vInOutField.cpos + vInOutField.str.size(),
454 vInOutField.index);
455 return true; // we not want to continue the field check
456 }
457
2/2
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 3 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 3 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
13 for (const auto& token : tokens) {
458
3/3
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 7 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 7 times.
1/1
✓ Call 0 invoked.
10 if (!m_parseValue(vInOutField, token)) {
459
1/1
✓ Branch 2 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
3 m_addError(INVALID_VALUES, vInOutField.cpos + token.first, vInOutField.index);
460 }
461 }
462 3 return true; // values, stop field checking
463 }
464
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
55 }
465 57 return false; // no values, continue field checking
466 }
467
468 195 void m_parseField(const Token& vToken) {
469
1/1
✓ Branch 1 taken 195 times.
1/1
✓ Call 0 invoked.
195 Field field;
470
1/1
✓ Branch 1 taken 195 times.
1/1
✓ Call 0 invoked.
195 field.str = vToken.second;
471
1/1
✓ Call 0 invoked.
195 field.index = static_cast<FieldIndex>(m_fields.size());
472 195 field.cpos = vToken.first;
473
3/3
✓ Branch 1 taken 195 times.
✓ Branch 3 taken 74 times.
✓ Branch 4 taken 121 times.
2/2
✓ Decision 'true' taken 74 times.
✓ Decision 'false' taken 121 times.
1/1
✓ Call 0 invoked.
195 if (!m_isInterval(field)) {
474
3/3
✓ Branch 1 taken 74 times.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 10 times.
2/2
✓ Decision 'true' taken 64 times.
✓ Decision 'false' taken 10 times.
1/1
✓ Call 0 invoked.
74 if (!m_isRange(field)) {
475
3/3
✓ Branch 1 taken 64 times.
✓ Branch 3 taken 57 times.
✓ Branch 4 taken 7 times.
2/2
✓ Decision 'true' taken 57 times.
✓ Decision 'false' taken 7 times.
1/1
✓ Call 0 invoked.
64 if (!m_isValues(field)) {
476
1/1
✓ Branch 1 taken 57 times.
1/1
✓ Call 0 invoked.
57 m_parseValue(field, vToken);
477 }
478 }
479 }
480
1/1
✓ Branch 1 taken 195 times.
1/1
✓ Call 0 invoked.
195 m_fields.push_back(field);
481
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
195 }
482
483 39 void m_parseExpression() {
484
1/1
✓ Call 0 invoked.
39 m_fields.clear();
485
2/2
✓ Branch 1 taken 39 times.
✓ Branch 4 taken 39 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
39 auto tokens = m_split(m_cronRule, " ");
486 39 auto count = static_cast<size_t>(FieldIndex::Count);
487
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 36 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 36 times.
1/1
✓ Call 0 invoked.
39 if (tokens.size() != count) {
488
1/1
✓ Branch 4 taken 3 times.
5/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
3 m_addError(INVALID_FIELDS_COUNT, tokens.back().first, tokens.size() - 1); // put the error on the last available field
489 }
490
2/2
✓ Branch 5 taken 195 times.
✓ Branch 6 taken 39 times.
2/2
✓ Decision 'true' taken 195 times.
✓ Decision 'false' taken 39 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
234 for (const auto& token : tokens) {
491
1/1
✓ Branch 1 taken 195 times.
1/1
✓ Call 0 invoked.
195 m_parseField(token);
492 }
493
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
39 }
494
495 61 std::string m_getErrorString(int32_t vFlag) const {
496
1/1
✓ Branch 1 taken 61 times.
1/1
✓ Call 0 invoked.
61 std::stringstream res;
497
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 39 times.
2/2
✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 39 times.
61 if (vFlag & INVALID_MINUTE) {
498
1/1
✓ Branch 1 taken 22 times.
1/1
✓ Call 0 invoked.
22 res << " Invalid minute.";
499 }
500
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 52 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 52 times.
61 if (vFlag & INVALID_HOUR) {
501
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 res << " Invalid hour.";
502 }
503
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 52 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 52 times.
61 if (vFlag & INVALID_MONTH_DAY) {
504
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 res << " Invalid month day.";
505 }
506
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 52 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 52 times.
61 if (vFlag & INVALID_MONTH) {
507
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 res << " Invalid month.";
508 }
509
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 52 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 52 times.
61 if (vFlag & INVALID_WEEK_DAY) {
510
1/1
✓ Branch 1 taken 9 times.
1/1
✓ Call 0 invoked.
9 res << " Invalid week day.";
511 }
512
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 58 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 58 times.
61 if (vFlag & INVALID_FIELDS_COUNT) {
513
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 res << " Invalid fields count.";
514 }
515
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 54 times.
2/2
✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 54 times.
61 if (vFlag & INVALID_CHAR) {
516
1/1
✓ Branch 1 taken 7 times.
1/1
✓ Call 0 invoked.
7 res << " Invalid char.";
517 }
518
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 36 times.
2/2
✓ Decision 'true' taken 25 times.
✓ Decision 'false' taken 36 times.
61 if (vFlag & INVALID_INTERVAL) {
519
1/1
✓ Branch 1 taken 25 times.
1/1
✓ Call 0 invoked.
25 res << " Invalid interval.";
520 }
521
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 53 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 53 times.
61 if (vFlag & INVALID_RANGE) {
522
1/1
✓ Branch 1 taken 8 times.
1/1
✓ Call 0 invoked.
8 res << " Invalid range.";
523 }
524
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 56 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 56 times.
61 if (vFlag & INVALID_VALUES) {
525
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 res << " Invalid values.";
526 }
527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 61 times.
61 if (vFlag & INVALID_FIELD) {
528
0/1
✗ Call 0 not invoked.
res << " Invalid field.";
529 }
530
1/1
✓ Branch 1 taken 61 times.
1/1
✓ Call 0 invoked.
122 return res.str();
531
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
61 }
532
533 90 bool m_checkTimeForField(FieldIndex vFieldIndex, int32_t vValue) const {
534
1/1
✓ Call 0 invoked.
90 const auto& field = m_fields.at(static_cast<size_t>(vFieldIndex));
535
5/6
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
90 switch (field.type) {
536
1/1
✓ Decision 'true' taken 28 times.
28 case FieldType::WILDCARD: { // '*' is valid for all values
537 28 return true;
538 }
539
1/1
✓ Decision 'true' taken 32 times.
32 case FieldType::VALUE: { // a == v
540 32 return (field.value == vValue);
541 }
542
1/1
✓ Decision 'true' taken 11 times.
11 case FieldType::INTERVAL: { // each v
543 11 return ((vValue % field.interval) == 0);
544 }
545
1/1
✓ Decision 'true' taken 10 times.
10 case FieldType::RANGE: { // a > v > b
546
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
17 return (vValue >= field.range.first && //
547
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
17 vValue <= field.range.second);
548 }
549
1/1
✓ Decision 'true' taken 9 times.
9 case FieldType::VALUES: { // a == v or b == v or ..
550
1/1
✓ Branch 2 taken 9 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
9 return (field.values.find(vValue) != field.values.end());
551 }
552
0/1
✗ Decision 'true' not taken.
case FieldType::Count:
553
0/1
✗ Decision 'true' not taken.
default: break;
554 }
555 return false;
556 }
557 };
558
559 } // namespace time
560 } // namespace ez
561
562 ////////////////////////////////////////////////////////////////////////////
563 ////////////////////////////////////////////////////////////////////////////
564 ////////////////////////////////////////////////////////////////////////////
565
566 #ifdef _MSC_VER
567 #pragma warning(pop)
568 #elif defined(__GNUC__) || defined(__clang__)
569 #pragma GCC diagnostic pop
570 #endif
571
572 ////////////////////////////////////////////////////////////////////////////
573 ////////////////////////////////////////////////////////////////////////////
574 ////////////////////////////////////////////////////////////////////////////
575

Directory: include/ezlibs/
File: ezArgs.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 201 227 88.5%
Functions: 25 25 100.0%
Branches: 194 256 75.8%
Decisions: 95 122 77.9%
Calls: 257 386 66.6%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezArgs is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include "ezOS.hpp"
30
31 #include <vector>
32 #include <string>
33 #include <cstdio> // FILENAME_MAX
34 #include <cstdint> // int32_t
35 #include <iostream>
36 #include <stdexcept>
37 #include <algorithm>
38
39 #include "ezStr.hpp"
40
41 #include "ezLog.hpp"
42
43 namespace ez {
44
45 class Args {
46 private:
47 class Argument {
48 friend class Args;
49
50 private:
51 std::vector<std::string> m_base_args; // base args
52 std::set<std::string> m_full_args; // full args
53 char one_char_arg = 0;
54 std::string m_help_text;
55 std::string m_help_var_name;
56 std::string m_type;
57 bool m_required = false;
58 char m_delimiter = 0; // delimiter used for arguments : toto a, toto=a, toto:a, etc...
59 bool m_is_present = false; // found during parsing
60 bool m_has_value = false; // found during parsing
61 std::string m_value; // value
62
63 public:
64
6/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
26 Argument() = default;
65
66 25 Argument &help(const std::string &vHelp, const std::string &vVarName = {}) {
67
1/1
✓ Call 0 invoked.
25 m_help_text = vHelp;
68
1/1
✓ Call 0 invoked.
25 m_help_var_name = vVarName;
69 25 return *this;
70 }
71
72 Argument &def(const std::string &vDefValue) {
73 m_value = vDefValue;
74 return *this;
75 }
76
77 Argument &type(const std::string &vType) {
78 m_type = vType;
79 return *this;
80 }
81
82 9 Argument &delimiter(char vDelimiter) {
83 9 m_delimiter = vDelimiter;
84 9 return *this;
85 }
86
87 Argument &required(bool vValue) {
88 m_required = vValue;
89 return *this;
90 }
91
92 private:
93 typedef std::pair<std::string, std::string> HelpCnt;
94
95 12 HelpCnt m_getHelp(bool vPositional, size_t &vInOutFirstColSize) const {
96
1/1
✓ Call 0 invoked.
12 HelpCnt res;
97
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
12 std::stringstream ss;
98
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 12 times.
12 if (vPositional) {
99
0/1
✗ Call 0 not invoked.
std::string token = m_help_var_name;
100
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/1
✗ Call 0 not invoked.
if (token.empty()) {
101
0/3
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
token = *(m_base_args.begin());
102 }
103
0/2
✗ Call 0 not invoked.
✗ Call 3 not invoked.
ss << " " << token;
104
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
} else {
105 12 size_t idx = 0;
106
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
12 ss << " ";
107
2/2
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 12 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 12 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
30 for (const auto &arg : m_base_args) {
108
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 12 times.
18 if (idx++ > 0) {
109
1/1
✓ Branch 1 taken 6 times.
1/1
✓ Call 0 invoked.
6 ss << ", ";
110 }
111
1/1
✓ Branch 1 taken 18 times.
1/1
✓ Call 0 invoked.
18 ss << arg;
112 }
113
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 6 times.
1/1
✓ Call 0 invoked.
12 if (!m_help_var_name.empty()) {
114
2/2
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
6 ss << " " << m_help_var_name;
115 }
116 }
117
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
12 auto ret = ss.str();
118
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 7 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 7 times.
1/1
✓ Call 0 invoked.
12 if (vInOutFirstColSize < ret.size()) {
119
1/1
✓ Call 0 invoked.
5 vInOutFirstColSize = ret.size();
120 }
121
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
24 return std::make_pair(ret, m_help_text);
122
3/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
12 }
123 };
124
125 private:
126 std::string m_AppName;
127 std::string m_HelpHeader;
128 std::string m_HelpFooter;
129 std::string m_HelpDescription;
130 Argument m_HelpArgument;
131 std::vector<Argument> m_Positionals;
132 std::vector<Argument> m_Optionals;
133
134 public:
135 Args() = default;
136
7/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
12 virtual ~Args() = default;
137
7/7
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✓ Call 6 invoked.
6 Args(const std::string &vName) : m_AppName(vName) {
138
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 6 times.
1/1
✓ Call 0 invoked.
6 if (vName.empty()) {
139
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
throw std::runtime_error("Name cant be empty");
140 }
141
4/4
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 8 taken 6 times.
✓ Branch 11 taken 6 times.
8/11
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 14 invoked.
✓ Call 15 invoked.
✗ Call 16 not invoked.
✗ Call 17 not invoked.
✗ Call 18 not invoked.
18 m_addOptional(m_HelpArgument, "-h/--help").help("Show the usage");
142
0/7
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
6 }
143
144 2 Args &addHeader(const std::string &vHeader) {
145
1/1
✓ Call 0 invoked.
2 m_HelpHeader = vHeader;
146 2 return *this;
147 }
148
149 2 Args &addFooter(const std::string &vFooter) {
150
1/1
✓ Call 0 invoked.
2 m_HelpFooter = vFooter;
151 2 return *this;
152 }
153
154 1 Args &addDescription(const std::string &vDescription) {
155
1/1
✓ Call 0 invoked.
1 m_HelpDescription = vDescription;
156 1 return *this;
157 }
158
159 4 Argument &addArgument(const std::string &vKey) {
160
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
4 if (vKey.empty()) {
161
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
throw std::runtime_error("argument cant be empty");
162 }
163
1/1
✓ Call 0 invoked.
4 Argument res;
164 4 res.m_required = true;
165
1/1
✓ Branch 1 taken 4 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
4 res.m_base_args = ez::str::splitStringToVector(vKey, '/');
166
2/2
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 4 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
8 for (const auto &a : res.m_base_args) {
167
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 res.m_full_args.emplace(a);
168 }
169
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 m_Positionals.push_back(res);
170
1/1
✓ Call 0 invoked.
8 return m_Positionals.back();
171
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
4 }
172
173 16 Argument &addOptional(const std::string &vKey) {
174
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 16 times.
1/1
✓ Call 0 invoked.
16 if (vKey.empty()) {
175
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
throw std::runtime_error("optinnal cant be empty");
176 }
177
1/1
✓ Call 0 invoked.
16 Argument res;
178
1/1
✓ Branch 1 taken 16 times.
1/1
✓ Call 0 invoked.
16 m_addOptional(res, vKey);
179
1/1
✓ Branch 1 taken 16 times.
1/1
✓ Call 0 invoked.
16 m_Optionals.push_back(res);
180
1/1
✓ Call 0 invoked.
32 return m_Optionals.back();
181
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
16 }
182
183 // is token present
184 22 bool isPresent(const std::string &vKey) {
185
1/1
✓ Call 0 invoked.
22 auto *ptr = m_getArgumentPtr(vKey, true);
186
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 2 times.
22 if (ptr != nullptr) {
187 20 return ptr->m_is_present;
188 }
189 2 return false;
190 }
191
192 // is token have value
193 10 bool hasValue(const std::string &vKey) {
194
1/1
✓ Call 0 invoked.
10 auto *ptr = m_getArgumentPtr(vKey, true);
195
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 1 times.
10 if (ptr != nullptr) {
196 9 return ptr->m_has_value;
197 }
198 1 return false;
199 }
200
201 template <typename T>
202 42 T getValue(const std::string &vKey, bool vNoExcept = false) const {
203
1/1
✓ Call 0 invoked.
42 auto *ptr = m_getArgumentPtr(vKey, vNoExcept);
204
6/6
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 10 times.
2/2
✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 20 times.
1/1
✓ Call 2 invoked.
42 if (ptr != nullptr && !ptr->m_value.empty()) {
205
1/1
✓ Call 0 invoked.
22 return m_convertString<T>(ptr->m_value);
206 }
207
1/1
✓ Call 0 invoked.
20 return {};
208 }
209
210 4 std::string getHelp( //
211 const std::string &vPositionalHeader = "Positionnal arguments",
212 const std::string &vOptionalHeader = "Optional arguments") const {
213
1/1
✓ Call 0 invoked.
4 std::string token;
214
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::stringstream ss;
215
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
4 if (!m_HelpHeader.empty()) {
216
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
2 ss << m_HelpHeader << std::endl << std::endl;
217 }
218
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
4 ss << m_getCmdLineHelp();
219
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 ss << std::endl;
220
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
4 if (!m_HelpDescription.empty()) {
221
4/4
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
1 ss << std::endl << " " << m_HelpDescription << std::endl;
222 }
223
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
4 ss << m_getHelpDetails(vPositionalHeader, vOptionalHeader);
224
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
4 if (!m_HelpFooter.empty()) {
225
3/3
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
2 ss << std::endl << m_HelpFooter << std::endl;
226 }
227
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
8 return ss.str();
228
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
4 }
229
230
5/5
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
8/11
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 16 invoked.
✓ Call 17 invoked.
✗ Call 18 not invoked.
✗ Call 19 not invoked.
✗ Call 20 not invoked.
20 void printHelp() const { std::cout << getHelp() << std::endl; }
231
232 6 bool parse(const int32_t vArgc, char **vArgv, const int32_t vStartIdx = 1U) {
233 6 size_t positional_idx = 0;
234
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 5 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 5 times.
20 for (int32_t idx = vStartIdx; idx < vArgc; ++idx) {
235
2/2
✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
15 std::string arg = m_trim(vArgv[idx]);
236
237 // print help
238
3/3
✓ Branch 2 taken 15 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 14 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 14 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
15 if (m_HelpArgument.m_full_args.find(arg) != m_HelpArgument.m_full_args.end()) {
239
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 printHelp();
240 1 return true;
241 }
242
243 // get args values
244
1/1
✓ Branch 1 taken 14 times.
1/1
✓ Call 0 invoked.
14 std::string token = arg;
245
1/1
✓ Call 0 invoked.
14 std::string value;
246 14 bool is_optional = false;
247 14 bool check_for_value = false;
248
2/2
✓ Branch 5 taken 37 times.
✓ Branch 6 taken 14 times.
2/2
✓ Decision 'true' taken 37 times.
✓ Decision 'false' taken 14 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
51 for (auto &arg_ref : m_Optionals) {
249 37 check_for_value = false;
250
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 13 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 13 times.
37 if (arg_ref.m_delimiter != 0) {
251
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 10 times.
2/2
✓ Decision 'true' taken 14 times.
✓ Decision 'false' taken 10 times.
24 if (arg_ref.m_delimiter != ' ') {
252
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 11 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 11 times.
1/1
✓ Call 0 invoked.
14 if (token.find(arg_ref.m_delimiter) != std::string::npos) {
253
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 auto arr = ez::str::splitStringToVector(token, arg_ref.m_delimiter);
254
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
3 if (arr.size() == 2) {
255
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
3 token = arr.at(0);
256
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
3 value = arr.at(1);
257 } else {
258
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/1
✗ Call 0 not invoked.
if (arr.size() < 2) {
259
0/10
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
✗ Call 14 not invoked.
✗ Call 15 not invoked.
throw std::runtime_error("bad parsing of key \"" + token + "\". no value");
260
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/1
✗ Call 0 not invoked.
} else if (arr.size() > 2) {
261
0/10
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 10 not invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
✗ Call 14 not invoked.
✗ Call 15 not invoked.
throw std::runtime_error("bad parsing of key \"" + token + "\". more than one value");
262 }
263 }
264
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
3 }
265 }
266 }
267
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 21 times.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 21 times.
37 if (arg_ref.one_char_arg != 0) {
268
1/1
✓ Call 0 invoked.
16 auto p = token.find(arg_ref.one_char_arg);
269
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 7 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 7 times.
16 if (p != std::string::npos) {
270 9 arg_ref.m_is_present = true;
271 9 is_optional = true;
272
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 7 times.
1/1
✓ Call 0 invoked.
9 if (p == (token.size() - 1)) {
273 2 check_for_value = true;
274 }
275 }
276
3/3
✓ Branch 2 taken 21 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 13 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 13 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
21 } else if (arg_ref.m_full_args.find(token) != arg_ref.m_full_args.end()) {
277 8 arg_ref.m_is_present = true;
278 8 is_optional = true;
279 8 check_for_value = true;
280 }
281
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 27 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 27 times.
37 if (check_for_value) {
282
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 6 times.
10 if (arg_ref.m_delimiter == ' ') {
283
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
4 if ((idx + 1) < vArgc) {
284
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
4 auto *existingArg = m_getArgumentPtr(vArgv[idx + 1], true);
285
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1 times.
4 if (!existingArg) {
286
1/1
✓ Branch 1 taken 3 times.
1/1
✓ Call 0 invoked.
3 arg_ref.m_value = vArgv[++idx];
287 3 arg_ref.m_has_value = true;
288 }
289 }
290
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1 times.
6 } else if (arg_ref.m_delimiter != 0) {
291
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 auto *existingArg = m_getArgumentPtr(value, true);
292
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
5 if (!existingArg) {
293
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 arg_ref.m_value = value;
294 5 arg_ref.m_has_value = true;
295 }
296 }
297 }
298 }
299
300 // positionals
301
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 10 times.
14 if (!is_optional) {
302
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (positional_idx < m_Positionals.size()) {
303
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 auto &positional = m_Positionals.at(positional_idx);
304
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 positional.m_value = arg;
305 4 positional.m_has_value = true;
306 4 ++positional_idx;
307 }
308 }
309
3/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
15 }
310
311
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 5 times.
5 if (vArgc == 1 && // only the app path default argument
312
0/1
✗ Call 0 not invoked.
!m_Positionals.empty()) { // some positionnal are wanted
313
0/1
✗ Call 0 not invoked.
printHelp();
314 }
315
316 5 return true;
317 }
318
319 private:
320 62 const Argument *m_getArgumentPtr(const std::string &vKey, bool vNoExcept = false) const {
321 62 const Argument *ret = nullptr;
322
2/2
✓ Branch 5 taken 30 times.
✓ Branch 6 taken 62 times.
2/2
✓ Decision 'true' taken 30 times.
✓ Decision 'false' taken 62 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
92 for (const auto &arg : m_Positionals) {
323
3/3
✓ Branch 2 taken 30 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 22 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 22 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
30 if (arg.m_full_args.find(vKey) != arg.m_full_args.end()) {
324 8 ret = &arg;
325 }
326 }
327
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 8 times.
2/2
✓ Decision 'true' taken 54 times.
✓ Decision 'false' taken 8 times.
62 if (ret == nullptr) {
328
2/2
✓ Branch 5 taken 196 times.
✓ Branch 6 taken 54 times.
2/2
✓ Decision 'true' taken 196 times.
✓ Decision 'false' taken 54 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
250 for (const auto &arg : m_Optionals) {
329
3/3
✓ Branch 2 taken 196 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 154 times.
2/2
✓ Decision 'true' taken 42 times.
✓ Decision 'false' taken 154 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
196 if (arg.m_full_args.find(vKey) != arg.m_full_args.end()) {
330 42 ret = &arg;
331 }
332 }
333 }
334
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 62 times.
62 if (ret == nullptr && vNoExcept == false) {
335
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
throw std::runtime_error("Argument not found");
336 }
337 62 return ret;
338 }
339
340 22 Argument &m_addOptional(Argument &vInOutArgument, const std::string &vKey) {
341
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 22 times.
1/1
✓ Call 0 invoked.
22 if (vKey.empty()) {
342
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
throw std::runtime_error("optinnal cant be empty");
343 }
344
1/1
✓ Branch 1 taken 22 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✗ Call 5 not invoked.
22 vInOutArgument.m_base_args = ez::str::splitStringToVector(vKey, '/');
345
2/2
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 22 times.
2/2
✓ Decision 'true' taken 34 times.
✓ Decision 'false' taken 22 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
56 for (const auto &a : vInOutArgument.m_base_args) {
346
1/1
✓ Branch 1 taken 34 times.
1/1
✓ Call 0 invoked.
34 vInOutArgument.m_full_args.emplace(a);
347 }
348
2/2
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 22 times.
2/2
✓ Decision 'true' taken 34 times.
✓ Decision 'false' taken 22 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
56 for (const auto &arg : vInOutArgument.m_base_args) {
349 // tofix : may fail if arg is --toto-titi.
350 // we will get titi but we want toto-titi
351
2/2
✓ Branch 1 taken 34 times.
✓ Branch 4 taken 34 times.
4/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
34 vInOutArgument.m_full_args.emplace(m_trim(arg));
352 }
353
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 14 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
22 vInOutArgument.one_char_arg = (vKey.size() == 1U) ? vKey[0] : 0;
354 22 return vInOutArgument;
355 }
356
357 4 std::string m_getCmdLineHelp() const {
358
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::stringstream ss;
359
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
4 ss << " Usage : " << m_AppName;
360
2/2
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 4 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 4 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
16 for (const auto &arg : m_Optionals) {
361
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
12 ss << " [";
362 12 size_t idx = 0;
363
2/2
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 12 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 12 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
30 for (const auto &o : arg.m_base_args) {
364
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 12 times.
18 if (idx++ > 0) {
365
1/1
✓ Branch 1 taken 6 times.
1/1
✓ Call 0 invoked.
6 ss << ':';
366 }
367
1/1
✓ Branch 1 taken 18 times.
1/1
✓ Call 0 invoked.
18 ss << o;
368 }
369
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 6 times.
1/1
✓ Call 0 invoked.
12 if (!arg.m_help_var_name.empty()) {
370
2/2
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
6 ss << " " << arg.m_help_var_name;
371 }
372
1/1
✓ Branch 1 taken 12 times.
1/1
✓ Call 0 invoked.
12 ss << "]";
373 }
374
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4 times.
3/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✓ Call 4 invoked.
4 for (const auto &arg : m_Positionals) {
375
0/1
✗ Call 0 not invoked.
std::string token = arg.m_help_var_name;
376
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/1
✗ Call 0 not invoked.
if (token.empty()) {
377
0/3
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
token = *(arg.m_base_args.begin());
378 }
379
0/2
✗ Call 0 not invoked.
✗ Call 3 not invoked.
ss << " " << token;
380 }
381
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
8 return ss.str();
382
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
4 }
383
384 4 std::string m_getHelpDetails( //
385 const std::string &vPositionalHeader,
386 const std::string &vOptionalHeader) const {
387 // collect infos with padding
388 4 size_t first_col_size = 0U;
389
1/1
✓ Call 0 invoked.
4 std::vector<Argument::HelpCnt> cnt_pos;
390
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4 times.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✓ Call 3 invoked.
4 for (const auto &arg : m_Positionals) {
391
0/5
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
cnt_pos.push_back(arg.m_getHelp(true, first_col_size));
392 }
393
1/1
✓ Call 0 invoked.
4 std::vector<Argument::HelpCnt> cnt_opt;
394
2/2
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 4 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 4 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
16 for (const auto &opt : m_Optionals) {
395
2/2
✓ Branch 1 taken 12 times.
✓ Branch 4 taken 12 times.
4/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
12 cnt_opt.push_back(opt.m_getHelp(false, first_col_size));
396 }
397 // display
398 4 first_col_size += 4U;
399
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 std::stringstream ss;
400
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
4 if (!cnt_pos.empty()) {
401
0/5
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 9 not invoked.
✗ Call 12 not invoked.
ss << std::endl << " " << vPositionalHeader << " : " << std::endl;
402
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
for (const auto &it : cnt_pos) {
403
0/9
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 7 not invoked.
✗ Call 10 not invoked.
✗ Call 13 not invoked.
✗ Call 16 not invoked.
✗ Call 17 not invoked.
✗ Call 18 not invoked.
ss << it.first << std::string(first_col_size - it.first.size(), ' ') << it.second << std::endl;
404 }
405 }
406
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 4 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
4 if (!cnt_opt.empty()) {
407
5/5
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 10 taken 4 times.
✓ Branch 13 taken 4 times.
5/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
4 ss << std::endl << " " << vOptionalHeader << " : " << std::endl;
408
2/2
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 4 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 4 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
16 for (const auto &it : cnt_opt) {
409
5/5
✓ Branch 1 taken 12 times.
✓ Branch 5 taken 12 times.
✓ Branch 8 taken 12 times.
✓ Branch 11 taken 12 times.
✓ Branch 14 taken 12 times.
8/9
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 13 invoked.
✓ Call 16 invoked.
✓ Call 17 invoked.
✗ Call 18 not invoked.
36 ss << it.first << std::string(first_col_size - it.first.size(), ' ') << it.second << std::endl;
410 }
411 }
412
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
8 return ss.str();
413
3/6
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
4 }
414
415 // remove the first '-' of a token
416 49 std::string m_trim(const std::string &vToken) {
417
1/1
✓ Call 0 invoked.
49 auto short_last_minus = vToken.find_first_not_of("-");
418
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 49 times.
✗ Decision 'false' not taken.
49 if (short_last_minus != std::string::npos) {
419
1/1
✓ Call 0 invoked.
49 return vToken.substr(short_last_minus);
420 }
421
0/1
✗ Call 0 not invoked.
return {};
422 }
423
424 template <typename T>
425 22 T m_convertString(const std::string &str) const {
426
1/1
✓ Branch 1 taken 11 times.
1/1
✓ Call 0 invoked.
22 std::istringstream iss(str);
427
1/1
✓ Call 0 invoked.
20 T value;
428
3/4
✓ Branch 1 taken 11 times.
✓ Branch 4 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 22 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
22 if (!(iss >> value)) {
429
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
throw std::runtime_error("Conversion failed");
430 }
431 42 return value;
432
1/3
✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
22 }
433 };
434
435 template <>
436 inline bool Args::m_convertString<bool>(const std::string &str) const {
437 if (str == "true" || str == "1") {
438 return true;
439 } else if (str == "false" || str == "0") {
440 return false;
441 }
442 throw std::runtime_error("Invalid boolean string");
443 }
444 } // namespace ez
445

Directory: include/ezlibs/
File: ezBmp.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 50 53 94.3%
Functions: 6 6 100.0%
Branches: 16 22 72.7%
Decisions: 8 12 66.7%
Calls: 20 25 80.0%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezBmp is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #ifndef EZ_BMP
30 #define EZ_BMP
31 #endif // EZ_BMP
32
33 #include <fstream>
34 #include <vector>
35 #include <cstdint>
36 #include <stdexcept>
37 #include <string>
38
39 namespace ez {
40 namespace img {
41
42 /*
43 Bitmap picture file saver
44
45 ez::img::Bmp()
46 .setSize(10,10) // width, height 10
47 .setPixel(0,0,255,100,200) // byte form
48 .setPixel(5,5,0.5,0.2,0.8) // linear float form
49 .save("test.bmp"); // save to file test.bmp
50 */
51
52 class Bmp {
53 friend class TestBmp;
54
55 private:
56 uint32_t m_width{};
57 uint32_t m_height{};
58 std::vector<uint8_t> m_pixels;
59
60 public:
61
1/1
✓ Call 0 invoked.
1 Bmp() = default;
62
1/1
✓ Call 0 invoked.
1 ~Bmp() = default;
63
64 1 Bmp& setSize(uint32_t vWidth, uint32_t vHeight) {
65
1/1
✓ Call 0 invoked.
1 m_width = std::move(vWidth);
66
1/1
✓ Call 0 invoked.
1 m_height = std::move(vHeight);
67
1/1
✓ Call 0 invoked.
1 m_pixels.resize(m_width * m_height * 3U);
68 1 return *this;
69 }
70
71 Bmp& clear() {
72 m_width = 0U;
73 m_height = 0U;
74 m_pixels.clear();
75 return *this;
76 }
77
78 10000 Bmp& setPixel(int32_t vX, int32_t vY, int32_t vRed, int32_t vGreen, int32_t vBlue) {
79 10000 auto x = static_cast<uint32_t>(vX);
80 10000 auto y = static_cast<uint32_t>(vY);
81
2/4
✓ Branch 0 taken 10000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10000 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 10000 times.
✗ Decision 'false' not taken.
10000 if (x >= 0 && y < m_width && y >= 0U && x < m_height) {
82 10000 size_t index = static_cast<size_t>((vY * m_width + vX) * 3);
83 // BMP save color in BGR
84
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10000 m_pixels[index++] = m_getByteFromInt32(vBlue);
85
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10000 m_pixels[index++] = m_getByteFromInt32(vGreen);
86
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10000 m_pixels[index] = m_getByteFromInt32(vRed);
87 }
88 10000 return *this;
89 }
90
91 Bmp& setPixel(int32_t vX, int32_t vY, float vRed, float vGreen, float vBlue) {
92 return setPixel(vX, //
93 vY,
94 m_getByteFromLinearFloat(vRed),
95 m_getByteFromLinearFloat(vGreen),
96 m_getByteFromLinearFloat(vBlue));
97 }
98
99 // Sauvegarde l'image en tant que fichier BMP
100 1 Bmp& write(const std::string& filename) {
101
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 std::ofstream file(filename, std::ios::binary);
102
2/3
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1/1
✓ Call 0 invoked.
1 if (!file) {
103
0/4
✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
throw std::runtime_error("Impossible d'ouvrir le fichier.");
104 }
105
106 1 int paddingSize = (4 - (m_width * 3) % 4) % 4;
107 1 int fileSize = 54 + (m_width * m_height * 3) + (m_height * paddingSize);
108
109 // En-t�te de fichier BMP
110 1 uint8_t fileHeader[14] = {
111 'B',
112 'M', // Signature
113 0,
114 0,
115 0,
116 0, // Taille du fichier
117 0,
118 0,
119 0,
120 0, // R�serv�
121 54,
122 0,
123 0,
124 0 // Offset vers les donn�es d'image
125 };
126
127 // Ins�rer la taille du fichier dans l'en-t�te
128 1 fileHeader[2] = fileSize;
129 1 fileHeader[3] = fileSize >> 8;
130 1 fileHeader[4] = fileSize >> 16;
131 1 fileHeader[5] = fileSize >> 24;
132
133 // En-t�te d'information BMP
134 1 uint8_t infoHeader[40] = {
135 40, 0, 0, 0, // Taille de l'en-t�te d'information
136 0, 0, 0, 0, // Largeur
137 0, 0, 0, 0, // Hauteur
138 1, 0, // Nombre de plans (1)
139 24, 0, // Bits par pixel (24 bits)
140 0, 0, 0, 0, // Compression (aucune)
141 0, 0, 0, 0, // Taille de l'image (non compress�e)
142 0, 0, 0, 0, // R�solution horizontale (pixels par m�tre)
143 0, 0, 0, 0, // R�solution verticale (pixels par m�tre)
144 0, 0, 0, 0, // Couleurs dans la palette
145 0, 0, 0, 0 // Couleurs importantes
146 };
147
148 // Ins�rer la largeur et la hauteur dans l'en-t�te d'information
149 1 infoHeader[4] = m_width;
150 1 infoHeader[5] = m_width >> 8;
151 1 infoHeader[6] = m_width >> 16;
152 1 infoHeader[7] = m_width >> 24;
153 1 infoHeader[8] = m_height;
154 1 infoHeader[9] = m_height >> 8;
155 1 infoHeader[10] = m_height >> 16;
156 1 infoHeader[11] = m_height >> 24;
157
158 // �crire les en-t�tes dans le fichier
159
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 file.write(reinterpret_cast<char*>(fileHeader), sizeof(fileHeader));
160
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 file.write(reinterpret_cast<char*>(infoHeader), sizeof(infoHeader));
161
162 // �crire les donn�es des pixels
163
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 100 times.
✓ Decision 'false' taken 1 times.
101 for (int32_t y = static_cast<int32_t>(m_height - 1); y >= 0; --y) { // BMP commence du bas vers le haut
164
2/2
✓ Branch 0 taken 10000 times.
✓ Branch 1 taken 100 times.
2/2
✓ Decision 'true' taken 10000 times.
✓ Decision 'false' taken 100 times.
10100 for (int32_t x = 0; x < static_cast<int32_t>(m_width); ++x) {
165 10000 size_t index = static_cast<size_t>((y * m_width + x) * 3);
166
1/1
✓ Branch 2 taken 10000 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10000 file.write(reinterpret_cast<char*>(&m_pixels[index]), 3);
167 }
168 // Ajout de padding si n�cessaire
169 100 uint8_t padding[3] = {0, 0, 0};
170
1/1
✓ Branch 1 taken 100 times.
1/1
✓ Call 0 invoked.
100 file.write(reinterpret_cast<char*>(padding), paddingSize);
171 }
172
173
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 file.close();
174 1 return *this;
175
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
1 }
176
177 private:
178 30000 uint8_t m_getByteFromInt32(int32_t vValue) {
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30000 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 30000 times.
30000 if (vValue < 0) {
180 vValue = 0;
181 }
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30000 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 30000 times.
30000 if (vValue > 255) {
183 vValue = 255;
184 }
185 30000 return static_cast<uint8_t>(vValue);
186 }
187 uint8_t m_getByteFromLinearFloat(float vValue) {
188 if (vValue < 0.0f) {
189 vValue = 0.0f;
190 }
191 if (vValue > 1.0f) {
192 vValue = 1.0f;
193 }
194 return static_cast<uint8_t>(vValue * 255.0f);
195 }
196 };
197
198 } // namespace img
199 } // namespace ez
200

Directory: include/ezlibs/
File: ezVec4.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 57 58 98.3%
Functions: 128 128 100.0%
Branches: 33 44 75.0%
Decisions: 1 2 50.0%
Calls: 47 56 83.9%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 #ifndef EZ_TOOLS_VEC4
4 #define EZ_TOOLS_VEC4
5 #endif // EZ_TOOLS_VEC4
6
7 /*
8 MIT License
9
10 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 */
30
31 // ezVec4 is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
32
33 #include <cmath>
34 #include <string>
35 #include <vector>
36 #include <type_traits>
37
38 namespace ez {
39
40 // Restrict the template to relevant types only (e.g., disable bool)
41 template <typename T>
42 struct vec4 {
43 static_assert(!std::is_same<T, bool>::value, "vec4 cannot be instantiated with bool type");
44
45 T x = 0;
46 T y = 0;
47 T z = 0;
48 T w = 0;
49
50 // Default constructor
51 vec4() = default;
52
53 // Constructor with type conversion
54 template <typename U>
55 vec4(const vec4<U>& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)), z(static_cast<T>(a.z)), w(static_cast<T>(a.w)) {}
56
57 // Constructor with type conversion
58 template <typename U>
59 vec4(const U& a) : x(static_cast<T>(a.x)), y(static_cast<T>(a.y)), z(static_cast<T>(a.z)), w(static_cast<T>(a.w)) {}
60
61 // Constructor using vec2 components
62 vec4(const vec2<T>& xy, const vec2<T>& zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}
63
64 // Constructor using vec3 and a scalar
65 vec4(const vec3<T>& xyz, T w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
66
67 // Constructor with a single scalar for all components
68 vec4(T xyzw) : x(xyzw), y(xyzw), z(xyzw), w(xyzw) {}
69
70 // Constructor with specific values
71 338 vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
72
73 // Constructor from a string
74 vec4(const std::string& vec, char c = ';', vec4<T>* def = nullptr) {
75 if (def) {
76 x = def->x;
77 y = def->y;
78 z = def->z;
79 w = def->w;
80 }
81 std::vector<T> result = str::stringToNumberVector<T>(vec, c);
82 const size_t s = result.size();
83 if (s > 0)
84 x = result[0];
85 if (s > 1)
86 y = result[1];
87 if (s > 2)
88 z = result[2];
89 if (s > 3)
90 w = result[3];
91 }
92
93 // Alternate constructor from a string with size checking
94 vec4(const std::string& vec, char c = ';', int n = 4, vec4<T>* def = nullptr) {
95 if (def) {
96 x = def->x;
97 y = def->y;
98 z = def->z;
99 w = def->w;
100 }
101 std::vector<T> result = str::stringToNumberVector<T>(vec, c);
102 const size_t s = result.size();
103 if (static_cast<int>(s) != n) {
104 if (s == 1) {
105 x = y = z = w = result[0];
106 } else if (s == 2) {
107 x = y = result[0];
108 z = w = result[1];
109 } else if (s == 3) {
110 x = result[0];
111 y = result[1];
112 z = result[2];
113 }
114 } else {
115 if (s > 0)
116 x = result[0];
117 if (s > 1)
118 y = result[1];
119 if (s > 2)
120 z = result[2];
121 if (s > 3)
122 w = result[3];
123 }
124 }
125
126 // Indexing operator
127 T& operator[](size_t i) { return (&x)[i]; }
128
129 // Offset the vector
130
1/1
✓ Call 0 invoked.
12 vec4 Offset(T vX, T vY, T vZ, T vW) const { return vec4(x + vX, y + vY, z + vZ, w + vW); }
131
132 // Set the vector's components
133 12 void Set(T vX, T vY, T vZ, T vW) {
134 12 x = vX;
135 12 y = vY;
136 12 z = vZ;
137 12 w = vW;
138 12 }
139
140 // Negation operator
141 4 vec4 operator-() const {
142 static_assert(std::is_signed<T>::value, "Negate is only valid for signed types");
143
1/1
✓ Call 0 invoked.
4 return vec4(-x, -y, -z, -w);
144 }
145
146 // Logical NOT operator, only for integral types
147 4 vec4 operator!() const {
148 static_assert(std::is_integral<T>::value, "Logical NOT is only valid for integral types");
149
1/1
✓ Call 0 invoked.
4 return vec4(!x, !y, !z, !w);
150 }
151
152 // Extract 2D and 3D vectors from 4D vector
153
1/1
✓ Call 0 invoked.
12 vec2<T> xy() const { return vec2<T>(x, y); }
154
155
1/1
✓ Call 0 invoked.
12 vec3<T> xyz() const { return vec3<T>(x, y, z); }
156
157
1/1
✓ Call 0 invoked.
12 vec2<T> zw() const { return vec2<T>(z, w); }
158
159 operator vec2<T>() const { return vec2<T>(x, y); }
160
161 operator vec3<T>() const { return vec3<T>(x, y, z); }
162
163 // Pre-increment and pre-decrement operators
164 12 vec4& operator++() {
165 12 ++x;
166 12 ++y;
167 12 ++z;
168 12 ++w;
169 12 return *this;
170 }
171
172 12 vec4& operator--() {
173 12 --x;
174 12 --y;
175 12 --z;
176 12 --w;
177 12 return *this;
178 }
179
180 // Post-increment and post-decrement operators
181 vec4 operator++(int) {
182 vec4 tmp = *this;
183 ++*this;
184 return tmp;
185 }
186
187 vec4 operator--(int) {
188 vec4 tmp = *this;
189 --*this;
190 return tmp;
191 }
192
193 // Compound assignment operators
194 void operator+=(T a) {
195 x += a;
196 y += a;
197 z += a;
198 w += a;
199 }
200
201 void operator+=(const vec4& v) {
202 x += v.x;
203 y += v.y;
204 z += v.z;
205 w += v.w;
206 }
207
208 void operator-=(T a) {
209 x -= a;
210 y -= a;
211 z -= a;
212 w -= a;
213 }
214
215 void operator-=(const vec4& v) {
216 x -= v.x;
217 y -= v.y;
218 z -= v.z;
219 w -= v.w;
220 }
221
222 void operator*=(T a) {
223 x *= a;
224 y *= a;
225 z *= a;
226 w *= a;
227 }
228
229 void operator*=(const vec4& v) {
230 x *= v.x;
231 y *= v.y;
232 z *= v.z;
233 w *= v.w;
234 }
235
236 void operator/=(T a) {
237 x /= a;
238 y /= a;
239 z /= a;
240 w /= a;
241 }
242
243 void operator/=(const vec4& v) {
244 x /= v.x;
245 y /= v.y;
246 z /= v.z;
247 w /= v.w;
248 }
249
250 // Size and position operations
251 vec2<T> SizeLBRT() const { return vec2<T>(z - x, w - y); } // Considers vec4 as a rectangle with LBRT (Left, Bottom, Right, Top)
252
253 vec2<T> pos() const { return xy(); }
254
255 vec2<T> size() const { return zw(); }
256
257 // Length of the vector
258
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
12 T length() const { return static_cast<T>(ez::sqrt(lengthSquared())); }
259
260 // Squared length of the vector
261 12 T lengthSquared() const { return x * x + y * y + z * z + w * w; }
262
263 // Normalize the vector
264 4 T normalize() {
265
1/1
✓ Call 0 invoked.
4 T _length = length();
266
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
4 if (_length < std::numeric_limits<T>::epsilon())
267 return static_cast<T>(0);
268 4 T _invLength = static_cast<T>(1) / _length;
269 4 x *= _invLength;
270 4 y *= _invLength;
271 4 z *= _invLength;
272 4 w *= _invLength;
273 4 return _length;
274 }
275
276 // Get a normalized copy of the vector
277 vec4 GetNormalized() const {
278 vec4 n = *this;
279 n.normalize();
280 return n;
281 }
282
283 // Check if all components are zero (AND)
284
5/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
24 bool emptyAND() const { return x == static_cast<T>(0) && y == static_cast<T>(0) && z == static_cast<T>(0) && w == static_cast<T>(0); }
285
286 // Check if any component is zero (OR)
287
5/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
24 bool emptyOR() const { return x == static_cast<T>(0) || y == static_cast<T>(0) || z == static_cast<T>(0) || w == static_cast<T>(0); }
288
289 // Sum of components
290 12 T sum() const { return x + y + z + w; }
291
292 // Sum of absolute values of components
293
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
8 T sumAbs() const { return ez::abs(x) + ez::abs(y) + ez::abs(z) + ez::abs(w); }
294
295 // Convert to string
296
10/10
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 7 taken 6 times.
✓ Branch 10 taken 6 times.
✓ Branch 13 taken 6 times.
✓ Branch 16 taken 6 times.
✓ Branch 19 taken 6 times.
✓ Branch 22 taken 6 times.
✓ Branch 25 taken 6 times.
✓ Branch 28 taken 6 times.
19/28
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✓ Call 18 invoked.
✓ Call 21 invoked.
✓ Call 24 invoked.
✓ Call 27 invoked.
✓ Call 30 invoked.
✓ Call 31 invoked.
✓ Call 32 invoked.
✓ Call 33 invoked.
✓ Call 34 invoked.
✓ Call 35 invoked.
✓ Call 36 invoked.
✓ Call 37 invoked.
✓ Call 38 invoked.
✗ Call 39 not invoked.
✗ Call 40 not invoked.
✗ Call 41 not invoked.
✗ Call 42 not invoked.
✗ Call 43 not invoked.
✗ Call 44 not invoked.
✗ Call 45 not invoked.
✗ Call 46 not invoked.
✗ Call 47 not invoked.
12 std::string string(char c = ';') const { return ez::str::toStr(x) + c + ez::str::toStr(y) + c + ez::str::toStr(z) + c + ez::str::toStr(w); }
297
298 // Minimum component
299
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
12 T mini() const { return ez::mini(x, ez::mini(y, ez::mini(z, w))); }
300
301 // Maximum component
302
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
12 T maxi() const { return ez::maxi(x, ez::maxi(y, ez::maxi(z, w))); }
303 };
304
305 // Operators for vec4
306 template <typename T>
307 inline vec4<T> operator+(vec4<T> v, T f) {
308 return vec4<T>(v.x + f, v.y + f, v.z + f, v.w + f);
309 }
310
311 template <typename T>
312 inline vec4<T> operator+(T f, vec4<T> v) {
313 return vec4<T>(v.x + f, v.y + f, v.z + f, v.w + f);
314 }
315
316 template <typename T>
317 12 inline vec4<T> operator+(vec4<T> v, const vec4<T>& f) {
318
1/1
✓ Call 0 invoked.
12 return vec4<T>(v.x + f.x, v.y + f.y, v.z + f.z, v.w + f.w);
319 }
320
321 template <typename T>
322 inline vec4<T> operator-(vec4<T> v, T f) {
323 return vec4<T>(v.x - f, v.y - f, v.z - f, v.w - f);
324 }
325
326 template <typename T>
327 inline vec4<T> operator-(T f, vec4<T> v) {
328 return vec4<T>(f - v.x, f - v.y, f - v.z, f - v.w);
329 }
330
331 template <typename T>
332 12 inline vec4<T> operator-(vec4<T> v, const vec4<T>& f) {
333
1/1
✓ Call 0 invoked.
12 return vec4<T>(v.x - f.x, v.y - f.y, v.z - f.z, v.w - f.w);
334 }
335
336 template <typename T>
337 12 inline vec4<T> operator*(vec4<T> v, T f) {
338
1/1
✓ Call 0 invoked.
12 return vec4<T>(v.x * f, v.y * f, v.z * f, v.w * f);
339 }
340
341 template <typename T>
342 inline vec4<T> operator*(T f, vec4<T> v) {
343 return vec4<T>(v.x * f, v.y * f, v.z * f, v.w * f);
344 }
345
346 template <typename T>
347 inline vec4<T> operator*(vec4<T> v, const vec4<T>& f) {
348 return vec4<T>(v.x * f.x, v.y * f.y, v.z * f.z, v.w * f.w);
349 }
350
351 template <typename T>
352 12 inline vec4<T> operator/(vec4<T> v, T f) {
353
1/1
✓ Call 0 invoked.
12 return vec4<T>(v.x / f, v.y / f, v.z / f, v.w / f);
354 }
355
356 template <typename T>
357 inline vec4<T> operator/(T f, vec4<T> v) {
358 return vec4<T>(f / v.x, f / v.y, f / v.z, f / v.w);
359 }
360
361 template <typename T>
362 inline vec4<T> operator/(vec4<T> v, const vec4<T>& f) {
363 return vec4<T>(v.x / f.x, v.y / f.y, v.z / f.z, v.w / f.w);
364 }
365
366 // Comparison operators
367 template <typename T>
368 inline bool operator<(vec4<T> v, const vec4<T>& f) {
369 return v.x < f.x && v.y < f.y && v.z < f.z && v.w < f.w;
370 }
371
372 template <typename T>
373 inline bool operator<(vec4<T> v, T f) {
374 return v.x < f && v.y < f && v.z < f && v.w < f;
375 }
376
377 template <typename T>
378 inline bool operator<(T f, vec4<T> v) {
379 return f < v.x && f < v.y && f < v.z && f < v.w;
380 }
381
382 template <typename T>
383 inline bool operator>(vec4<T> v, const vec4<T>& f) {
384 return v.x > f.x && v.y > f.y && v.z > f.z && v.w > f.w;
385 }
386
387 template <typename T>
388 inline bool operator>(vec4<T> v, T f) {
389 return v.x > f && v.y > f && v.z > f && v.w > f;
390 }
391
392 template <typename T>
393 inline bool operator>(T f, vec4<T> v) {
394 return f > v.x && f > v.y && f > v.z && f > v.w;
395 }
396
397 template <typename T>
398 inline bool operator<=(vec4<T> v, const vec4<T>& f) {
399 return v.x <= f.x && v.y <= f.y && v.z <= f.z && v.w <= f.w;
400 }
401
402 template <typename T>
403 inline bool operator<=(vec4<T> v, T f) {
404 return v.x <= f && v.y <= f && v.z <= f && v.w <= f;
405 }
406
407 template <typename T>
408 inline bool operator<=(T f, vec4<T> v) {
409 return f <= v.x && f <= v.y && f <= v.z && f <= v.w;
410 }
411
412 template <typename T>
413 inline bool operator>=(vec4<T> v, const vec4<T>& f) {
414 return v.x >= f.x && v.y >= f.y && v.z >= f.z && v.w >= f.w;
415 }
416
417 template <typename T>
418 inline bool operator>=(vec4<T> v, T f) {
419 return v.x >= f && v.y >= f && v.z >= f && v.w >= f;
420 }
421
422 template <typename T>
423 inline bool operator>=(T f, vec4<T> v) {
424 return f >= v.x && f >= v.y && f >= v.z && f >= v.w;
425 }
426
427 template <typename T>
428 20 inline bool operator==(vec4<T> v, const vec4<T>& f) {
429
5/8
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
20 return v.x == f.x && v.y == f.y && v.z == f.z && v.w == f.w;
430 }
431
432 template <typename T>
433 inline bool operator==(vec4<T> v, T f) {
434 return v.x == f && v.y == f && v.z == f && v.w == f;
435 }
436
437 template <typename T>
438 inline bool operator==(T f, vec4<T> v) {
439 return f == v.x && f == v.y && f == v.z && f == v.w;
440 }
441
442 template <typename T>
443 inline bool operator!=(vec4<T> v, const vec4<T>& f) {
444 return v.x != f.x || v.y != f.y || v.z != f.z || v.w != f.w;
445 }
446
447 template <typename T>
448 inline bool operator!=(vec4<T> v, T f) {
449 return v.x != f || v.y != f || v.z != f || v.w != f;
450 }
451
452 template <typename T>
453 inline bool operator!=(T f, vec4<T> v) {
454 return f != v.x || f != v.y || f != v.z || f != v.w;
455 }
456
457 // Utility functions
458 template <typename T>
459 inline vec4<T> mini(vec4<T> a, vec4<T> b) {
460 return vec4<T>(ez::mini(a.x, b.x), ez::mini(a.y, b.y), ez::mini(a.z, b.z), ez::mini(a.w, b.w));
461 }
462
463 template <typename T>
464 inline vec4<T> maxi(vec4<T> a, vec4<T> b) {
465 return vec4<T>(ez::maxi(a.x, b.x), ez::maxi(a.y, b.y), ez::maxi(a.z, b.z), ez::maxi(a.w, b.w));
466 }
467
468 template <typename T>
469 inline vec4<T> floor(vec4<T> a) {
470 return vec4<T>(ez::floor(a.x), ez::floor(a.y), ez::floor(a.z), ez::floor(a.w));
471 }
472
473 template <typename T>
474 inline vec4<T> ceil(vec4<T> a) {
475 return vec4<T>(ez::ceil(a.x), ez::ceil(a.y), ez::ceil(a.z), ez::ceil(a.w));
476 }
477
478 template <typename T>
479 inline vec4<T> abs(vec4<T> a) {
480 return vec4<T>(ez::abs(a.x), ez::abs(a.y), ez::abs(a.z), ez::abs(a.w));
481 }
482
483 template <typename T>
484 inline vec4<T> sign(vec4<T> a) {
485 return vec4<T>(a.x < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1),
486 a.y < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1),
487 a.z < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1),
488 a.w < static_cast<T>(0) ? static_cast<T>(-1) : static_cast<T>(1));
489 }
490
491 template <typename T>
492 inline vec4<T> sin(vec4<T> a) {
493 return vec4<T>(ez::sin(a.x), ez::sin(a.y), ez::sin(a.z), ez::sin(a.w));
494 }
495
496 template <typename T>
497 inline vec4<T> cos(vec4<T> a) {
498 return vec4<T>(ez::cos(a.x), ez::cos(a.y), ez::cos(a.z), ez::cos(a.w));
499 }
500
501 template <typename T>
502 inline vec4<T> tan(vec4<T> a) {
503 return vec4<T>(ez::tan(a.x), ez::tan(a.y), ez::tan(a.z), ez::tan(a.w));
504 }
505
506 // Type aliases for common vector types
507 using dvec4 = vec4<double>;
508 using fvec4 = vec4<float>;
509 using f32vec4 = vec4<float>;
510 using f64vec4 = vec4<double>;
511 using bvec4 = vec4<bool>;
512 using ivec4 = vec4<int>;
513 using i8vec4 = vec4<int8_t>;
514 using i16vec4 = vec4<int16_t>;
515 using i32vec4 = vec4<int32_t>;
516 using i64vec4 = vec4<int64_t>;
517 using u8vec4 = vec4<uint8_t>;
518 using u16vec4 = vec4<uint16_t>;
519 using uvec4 = vec4<uint32_t>;
520 using u32vec4 = vec4<uint32_t>;
521 using u64vec4 = vec4<uint64_t>;
522
523 // Specialization for float validation
524 inline bool valid(const fvec4& a) {
525 return floatIsValid(a.x) && floatIsValid(a.y) && floatIsValid(a.z) && floatIsValid(a.w);
526 }
527
528 // Float-specific comparison operators
529 5 inline bool operator==(const fvec4& v, const fvec4& f) {
530
7/8
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
4/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
5 return isEqual(f.x, v.x) && isEqual(f.y, v.y) && isEqual(f.z, v.z) && isEqual(f.w, v.w);
531 }
532
533 inline bool operator!=(const fvec4& v, const fvec4& f) {
534 return isDifferent(f.x, v.x) || isDifferent(f.y, v.y) || isDifferent(f.z, v.z) || isDifferent(f.w, v.w);
535 }
536
537 template <typename T>
538 inline std::istream& operator>>(std::istream& vIn, vec4<T>& vType) {
539 char separator;
540 if (vIn >> vType.x >> separator >> vType.y >> separator >> vType.z >> separator >> vType.w) {
541 if (separator != ';') {
542 vIn.setstate(std::ios::failbit);
543 }
544 }
545 return vIn;
546 }
547
548 template <typename T>
549 inline std::ostream& operator<<(std::ostream& vOut, const vec4<T>& vType) {
550 vOut << vType.x << ";" << vType.y << ";" << vType.z << ";" << vType.w;
551 return vOut;
552 }
553
554 } // namespace ez
555

Directory: include/ezlibs/
File: ezVdbWriter.hpp
Date: 2025-07-28 14:06:36
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 243 249 97.6%
Functions: 60 62 96.8%
Branches: 128 158 81.0%
Decisions: 26 34 76.5%
Calls: 216 254 85.0%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2022-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezVdb is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <unordered_map>
30 #include <iostream>
31 #include <cassert>
32 #include <iomanip>
33 #include <cstdint>
34 #include <sstream>
35 #include <cstring>
36 #include <limits>
37 #include <string>
38 #include <vector>
39 #include <memory>
40 #include <array>
41 #include <map>
42
43 #include "ezMath.hpp"
44
45 namespace ez {
46 namespace file {
47 namespace vdb {
48
49 120426 static void write_ptr(FILE* fp, const void* data, size_t elementSize, size_t count = 1) {
50
1/1
✓ Call 0 invoked.
120426 fwrite(data, elementSize, count, fp);
51 120426 }
52 41802 static void write_ptr(FILE* fp, void* data, size_t elementSize, size_t count = 1) {
53
1/1
✓ Call 0 invoked.
41802 fwrite(data, elementSize, count, fp);
54 41802 }
55
56 template <typename T>
57 82384 void write_data(FILE* fp, T data) {
58
1/1
✓ Call 0 invoked.
82384 write_ptr(fp, &data, sizeof(T));
59 82384 }
60
61 template <typename T>
62 1200 void write_data_arr(FILE* fp, T* data, size_t count) {
63
1/1
✓ Call 0 invoked.
1200 write_ptr(fp, data, sizeof(T), count);
64 1200 }
65
66 template <typename T>
67 240192 void write_data_arr(FILE* fp, const T* data, size_t count) {
68
1/1
✓ Call 0 invoked.
240192 write_ptr(fp, data, sizeof(T), count);
69 240192 }
70
71 330 static void write_string(FILE* fp, const std::string& str) {
72
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
330 write_ptr(fp, str.data(), sizeof(uint8_t), str.size());
73 330 }
74 60 inline void write_vec3i(FILE* fp, const std::array<int32_t, 3>& data) {
75
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
60 write_data_arr<int32_t>(fp, data.data(), 3);
76 60 }
77
78 320 inline void write_name(FILE* fp, const std::string& name) {
79
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
320 write_data<uint32_t>(fp, (uint32_t)name.size());
80
1/1
✓ Call 0 invoked.
320 write_string(fp, name);
81 320 }
82
83 60 inline void write_meta_string(FILE* fp, const std::string& name, const std::string& str) {
84
1/1
✓ Call 0 invoked.
60 write_name(fp, name);
85
2/2
✓ Branch 1 taken 60 times.
✓ Branch 4 taken 60 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
60 write_name(fp, "string");
86
1/1
✓ Call 0 invoked.
60 write_name(fp, str);
87 60 }
88
89 inline void write_meta_bool(FILE* fp, const std::string& name, bool flag) {
90 write_name(fp, name);
91 write_name(fp, "bool");
92 write_data<uint32_t>(fp, 1); // one byte is used to store the bool
93 write_data<uint8_t>(fp, flag ? 1 : 0);
94 }
95
96 40 inline void write_meta_vec3i(FILE* fp, const std::string& name, const std::array<int32_t, 3>& data) {
97
1/1
✓ Call 0 invoked.
40 write_name(fp, name);
98
2/2
✓ Branch 1 taken 40 times.
✓ Branch 4 taken 40 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
40 write_name(fp, "vec3i");
99
1/1
✓ Call 0 invoked.
40 write_data<uint32_t>(fp, 12U); // 12 bytes (4 bytes * 3) are used to store the vec3i
100
1/1
✓ Call 0 invoked.
40 write_vec3i(fp, data);
101 40 }
102
103 class ATree {
104 protected:
105 dAABBCC m_Volume;
106 std::string m_Name;
107
108 protected:
109 virtual bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, void* vDatas, size_t vByteSize, size_t vCount) = 0;
110
111 1800000 static uint32_t getBitIndex4(uint32_t vX, uint32_t vY, uint32_t vZ) {
112 1800000 const auto& x = vX & (uint32_t)(4096 - 1);
113 1800000 const auto& y = vY & (uint32_t)(4096 - 1);
114 1800000 const auto& z = vZ & (uint32_t)(4096 - 1);
115 1800000 uint32_t idx_3d[3] = {x >> 7, y >> 7, z >> 7};
116 1800000 uint64_t idx = idx_3d[2] | (idx_3d[1] << 5) | (idx_3d[0] << 10);
117 1800000 return static_cast<uint32_t>(idx);
118 }
119
120 1800000 static uint32_t getBitIndex3(uint32_t vX, uint32_t vY, uint32_t vZ) {
121 1800000 const auto& x = vX & (uint32_t)(128 - 1);
122 1800000 const auto& y = vY & (uint32_t)(128 - 1);
123 1800000 const auto& z = vZ & (uint32_t)(128 - 1);
124 1800000 uint32_t idx_3d[3] = {x >> 3, y >> 3, z >> 3};
125 1800000 uint64_t idx = idx_3d[2] | (idx_3d[1] << 4) | (idx_3d[0] << 8);
126 1800000 return static_cast<uint32_t>(idx);
127 }
128
129 1800000 static uint32_t getBitIndex0(uint32_t vX, uint32_t vY, uint32_t vZ) {
130 1800000 const auto& x = vX & (uint32_t)(8 - 1);
131 1800000 const auto& y = vY & (uint32_t)(8 - 1);
132 1800000 const auto& z = vZ & (uint32_t)(8 - 1);
133 1800000 uint32_t idx_3d[3] = {x >> 0, y >> 0, z >> 0};
134 1800000 uint64_t idx = idx_3d[2] | (idx_3d[1] << 3) | (idx_3d[0] << 6);
135 1800000 return static_cast<uint32_t>(idx);
136 }
137
138 80384 static int32_t count_trailing_zeros(uint64_t value) {
139 80384 int32_t count = 0;
140
3/4
✓ Branch 0 taken 1916136 times.
✓ Branch 1 taken 80384 times.
✓ Branch 2 taken 1916136 times.
✗ Branch 3 not taken.
0/1
? Decision couldn't be analyzed.
1996520 while ((value & 1) == 0 && value != 0) {
141 1916136 ++count;
142 1916136 value >>= 1;
143 }
144 80384 return count;
145 }
146
147 public:
148
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
20 ATree(const std::string& vName) : m_Name(vName) {
149 20 }
150
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
40 virtual ~ATree() = default;
151
152 virtual void write(FILE* vFp) = 0;
153 };
154
155 template <typename TType, size_t TCount>
156 class VdbTree : public ATree {
157 private:
158 struct Node3 {
159 uint64_t mask[8] = {};
160 std::array<TType, TCount> data[512] = {}; // data
161 };
162
163 struct Node4 {
164 uint64_t mask[64] = {};
165 std::map<uint32_t, Node3> nodes; // loc, node
166 };
167
168 struct Node5 {
169 uint64_t mask[512] = {};
170 std::map<uint32_t, Node4> nodes; // loc, node
171 };
172
173 360 void writeNode4EmptyHeader(FILE* fp, Node4* node) {
174
1/1
✓ Call 0 invoked.
360 write_data_arr<uint64_t>(fp, node->mask, 64);
175
4/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4/5
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 12 not invoked.
368 static std::vector<uint64_t> mask_arr_uint64_empty(64); // we dont use a std::array for not increase the bin size
176
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
360 write_data_arr<uint64_t>(fp, mask_arr_uint64_empty.data(), mask_arr_uint64_empty.size());
177
1/1
✓ Call 0 invoked.
360 write_data<uint8_t>(fp, 6);
178
4/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 178 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4/5
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 12 not invoked.
368 static std::vector<float> mask_arr_float_empty(4096);
179
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
360 write_data_arr<float>(fp, mask_arr_float_empty.data(), mask_arr_float_empty.size());
180 360 }
181
182 40 void writeNode5EmptyHeader(FILE* fp, Node5* node) {
183
1/1
✓ Branch 1 taken 20 times.
1/2
✓ Call 0 invoked.
✗ Call 3 not invoked.
40 write_vec3i(fp, {0, 0, 0});
184
1/1
✓ Call 0 invoked.
40 write_data_arr<uint64_t>(fp, node->mask, 512);
185
4/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4/5
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 12 not invoked.
48 static std::vector<uint64_t> mask_arr_uint64_empty(512); // we dont use a std::array for not increase the bin size
186
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
40 write_data_arr<uint64_t>(fp, mask_arr_uint64_empty.data(), mask_arr_uint64_empty.size());
187
1/1
✓ Call 0 invoked.
40 write_data<uint8_t>(fp, 6);
188
4/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
4/5
✓ Call 2 invoked.
✓ Call 5 invoked.
✓ Call 8 invoked.
✓ Call 9 invoked.
✗ Call 12 not invoked.
48 static std::vector<float> mask_arr_float_empty(32768);
189
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
40 write_data_arr<float>(fp, mask_arr_float_empty.data(), mask_arr_float_empty.size());
190 40 }
191
192 40 void writeTree(FILE* fp) {
193
1/1
✓ Call 0 invoked.
40 write_data<uint32_t>(fp, 1);
194
1/1
✓ Call 0 invoked.
40 write_data<float>(fp, 0);
195
1/1
✓ Call 0 invoked.
40 write_data<uint32_t>(fp, 0);
196
1/1
✓ Call 0 invoked.
40 write_data<uint32_t>(fp, 1);
197 40 auto& nodes5Ref = m_Nodes;
198
1/1
✓ Call 0 invoked.
40 writeNode5EmptyHeader(fp, &nodes5Ref);
199 40 size_t word5_idx = 0;
200
2/2
✓ Branch 0 taken 10240 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 10240 times.
✓ Decision 'false' taken 20 times.
20520 for (auto word5 : nodes5Ref.mask) {
201 20480 const auto& base_bit_4_idx = ((uint32_t)word5_idx++) * 64;
202
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 10240 times.
2/2
✓ Decision 'true' taken 180 times.
✓ Decision 'false' taken 10240 times.
20840 for (; word5 != 0; word5 &= word5 - 1) {
203
1/1
✓ Call 0 invoked.
360 const auto& bit_4_index = base_bit_4_idx + (uint32_t)count_trailing_zeros(word5);
204
1/1
✓ Branch 1 taken 180 times.
1/1
✓ Call 0 invoked.
360 auto& nodes4Ref = nodes5Ref.nodes.at(bit_4_index);
205
1/1
✓ Branch 1 taken 180 times.
1/1
✓ Call 0 invoked.
360 writeNode4EmptyHeader(fp, &nodes4Ref);
206 360 size_t word4_idx = 0;
207
2/2
✓ Branch 0 taken 11520 times.
✓ Branch 1 taken 180 times.
2/2
✓ Decision 'true' taken 11520 times.
✓ Decision 'false' taken 180 times.
23400 for (auto word4 : nodes4Ref.mask) {
208 23040 const auto& base_bit_3_idx = ((uint32_t)word4_idx++) * 64;
209
2/2
✓ Branch 0 taken 40012 times.
✓ Branch 1 taken 11520 times.
2/2
✓ Decision 'true' taken 40012 times.
✓ Decision 'false' taken 11520 times.
103064 for (; word4 != 0; word4 &= word4 - 1) {
210
1/1
✓ Call 0 invoked.
80024 const auto& bit_3_index = base_bit_3_idx + (uint32_t)count_trailing_zeros(word4);
211
1/1
✓ Branch 1 taken 40012 times.
1/1
✓ Call 0 invoked.
80024 const auto& nodes3Ref = nodes4Ref.nodes.at(bit_3_index);
212
1/1
✓ Branch 1 taken 40012 times.
1/1
✓ Call 0 invoked.
80024 write_data_arr<uint64_t>(fp, nodes3Ref.mask, 8);
213 }
214 }
215 }
216 }
217 40 word5_idx = 0;
218
2/2
✓ Branch 0 taken 10240 times.
✓ Branch 1 taken 20 times.
2/2
✓ Decision 'true' taken 10240 times.
✓ Decision 'false' taken 20 times.
20520 for (auto word5 : nodes5Ref.mask) {
219 20480 const auto& base_bit_4_idx = ((uint32_t)word5_idx++) * 64;
220
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 10240 times.
2/2
✓ Decision 'true' taken 180 times.
✓ Decision 'false' taken 10240 times.
20840 for (; word5 != 0; word5 &= word5 - 1) {
221
1/1
✓ Call 0 invoked.
360 const auto& bit_4_index = base_bit_4_idx + (uint32_t)count_trailing_zeros(word5);
222
1/1
✓ Branch 1 taken 180 times.
1/1
✓ Call 0 invoked.
360 const auto& nodes4Ref = nodes5Ref.nodes.at(bit_4_index);
223 360 size_t word4_idx = 0;
224
2/2
✓ Branch 0 taken 11520 times.
✓ Branch 1 taken 180 times.
2/2
✓ Decision 'true' taken 11520 times.
✓ Decision 'false' taken 180 times.
23400 for (auto word4 : nodes4Ref.mask) {
225 23040 const auto& base_bit_3_idx = ((uint32_t)word4_idx++) * 64;
226
2/2
✓ Branch 0 taken 40012 times.
✓ Branch 1 taken 11520 times.
2/2
✓ Decision 'true' taken 40012 times.
✓ Decision 'false' taken 11520 times.
103064 for (; word4 != 0; word4 &= word4 - 1) {
227
1/1
✓ Call 0 invoked.
80024 const auto& bit_3_index = base_bit_3_idx + (uint32_t)count_trailing_zeros(word4);
228
1/1
✓ Branch 1 taken 40012 times.
1/1
✓ Call 0 invoked.
80024 const auto& nodes3Ref = nodes4Ref.nodes.at(bit_3_index);
229
1/1
✓ Branch 1 taken 40012 times.
1/1
✓ Call 0 invoked.
80024 write_data_arr<uint64_t>(fp, nodes3Ref.mask, 8);
230
1/1
✓ Branch 1 taken 40012 times.
1/1
✓ Call 0 invoked.
80024 write_data<uint8_t>(fp, 6);
231
1/1
✓ Branch 1 taken 40012 times.
1/1
✓ Call 0 invoked.
80024 write_data_arr<std::array<TType, TCount>>(fp, nodes3Ref.data, 512);
232 }
233 }
234 }
235 }
236 40 }
237
238 40 void writeMetadata(FILE* fp) {
239 // Number of entries
240
1/1
✓ Call 0 invoked.
40 write_data<uint32_t>(fp, 5);
241
3/3
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
✓ Branch 7 taken 20 times.
5/8
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
160 write_meta_string(fp, "class", "unknown");
242
3/3
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
✓ Branch 7 taken 20 times.
5/8
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
120 write_meta_string(fp, "file_compression", "none");
243
2/2
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
3/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
80 write_meta_vec3i(fp, "file_bbox_max", {(int32_t)m_Volume.upperBound.x, (int32_t)m_Volume.upperBound.y, (int32_t)m_Volume.upperBound.z});
244
2/2
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
3/5
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
✗ Call 8 not invoked.
80 write_meta_vec3i(fp, "file_bbox_min", {(int32_t)m_Volume.lowerBound.x, (int32_t)m_Volume.lowerBound.y, (int32_t)m_Volume.lowerBound.z});
245
2/2
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
80 write_meta_string(fp, "name", m_Name);
246 40 }
247
248 40 void writeTransform(FILE* fp) {
249
2/2
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
40 write_name(fp, "UniformScaleTranslateMap");
250 // write Translation
251
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 const auto& center = m_Volume.GetCenter();
252
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, -center.x);
253
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, -center.y);
254
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, -center.z);
255 // write ScaleValues
256
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
257
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
258
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
259 // write VoxelSize
260
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
261
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
262
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
263 // write ScaleValuesInverse
264
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
265
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
266
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
267 // write InvScaleSqr
268
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
269
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
270
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 1.0);
271 // write InvTwiceScale;
272
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 0.5);
273
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 0.5);
274
1/1
✓ Branch 1 taken 20 times.
1/1
✓ Call 0 invoked.
40 write_data<double>(fp, 0.5);
275 40 }
276
277 // thoses functions must be specialized or derived
278 virtual std::string getTypeName() {
279
0/2
✗ Call 0 not invoked.
✗ Call 1 not invoked.
std::cout << "getTypeName is not specialized for your Type" << std::endl;
280 assert(0);
281 return "";
282 }
283
284 private:
285 Node5 m_Nodes;
286
287 public:
288
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
40 VdbTree(const std::string& vName) : ATree(vName) {
289 40 }
290
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
40 virtual ~VdbTree() = default;
291
292 3600000 bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, void* vDatas, size_t vByteSize, size_t vCount) override final {
293
3/6
✓ Branch 0 taken 1800000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1800000 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1800000 times.
✗ Branch 5 not taken.
1/2
✓ Decision 'true' taken 3600000 times.
✗ Decision 'false' not taken.
3600000 if (vDatas != nullptr && vByteSize == sizeof(TType) && vCount == TCount) {
294
1/1
✓ Branch 2 taken 1800000 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
3600000 m_Volume.Combine(ez::dvec3((float)vX, (float)vY, (float)vZ));
295
1/1
✓ Call 0 invoked.
3600000 const auto& bit_index_4 = getBitIndex4(vX, vY, vZ);
296
1/1
✓ Call 0 invoked.
3600000 const auto& bit_index_3 = getBitIndex3(vX, vY, vZ);
297
1/1
✓ Call 0 invoked.
3600000 const auto& bit_index_0 = getBitIndex0(vX, vY, vZ);
298
1/1
✓ Branch 1 taken 1800000 times.
1/1
✓ Call 0 invoked.
3600000 auto& nodes4Ref = m_Nodes.nodes[bit_index_4];
299
1/1
✓ Branch 1 taken 1800000 times.
1/1
✓ Call 0 invoked.
3600000 auto& nodes3Ref = nodes4Ref.nodes[bit_index_3];
300 3600000 m_Nodes.mask[bit_index_4 >> 6] |= static_cast<uint64_t>(1) << (bit_index_4 & (64 - 1)); // active the voxel 4
301 3600000 nodes4Ref.mask[bit_index_3 >> 6] |= static_cast<uint64_t>(1) << (bit_index_3 & (64 - 1)); // active the voxel 3
302 3600000 nodes3Ref.mask[bit_index_0 >> 6] |= static_cast<uint64_t>(1) << (bit_index_0 & (64 - 1)); // active the voxel 0
303 3600000 memcpy(&nodes3Ref.data[bit_index_0], vDatas, vByteSize * vCount);
304 3600000 return true;
305 }
306 return false;
307 }
308
309 900000 bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, const std::array<TType, TCount>& vDatas) {
310
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
900000 return addVoxel(vX, vY, vZ, const_cast<TType*>(vDatas.data()), sizeof(TType), TCount);
311 }
312
313 40 void write(FILE* fp) override {
314
1/1
✓ Call 0 invoked.
40 write_name(fp, m_Name);
315
2/2
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
40 write_name(fp, getTypeName());
316
1/1
✓ Call 0 invoked.
40 write_data<uint32_t>(fp, 0); // Instance parent
317
1/1
✓ Call 0 invoked.
40 uint64_t stream_pos = ftell(fp);
318
1/1
✓ Call 0 invoked.
40 write_data<uint64_t>(fp, stream_pos + sizeof(uint64_t) * 3); // grid pos
319
1/1
✓ Call 0 invoked.
40 write_data<uint64_t>(fp, 0); // block pos
320
1/1
✓ Call 0 invoked.
40 write_data<uint64_t>(fp, 0); // end pos
321
1/1
✓ Call 0 invoked.
40 write_data<uint32_t>(fp, 0); // compression
322
1/1
✓ Call 0 invoked.
40 writeMetadata(fp);
323
1/1
✓ Call 0 invoked.
40 writeTransform(fp);
324
1/1
✓ Call 0 invoked.
40 writeTree(fp);
325 40 }
326 };
327
328 template <typename TType>
329 class VdbScalarGrid : public VdbTree<TType, 1> {
330 protected:
331 std::string getTypeName() override {
332 std::cout << "getTypeName is not specialized for your Type" << std::endl;
333 assert(0);
334 return "";
335 }
336
337 public:
338
1/1
✓ Call 0 invoked.
10 VdbScalarGrid(const std::string& vName) : VdbTree<TType, 1>(vName) {
339 10 }
340
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
40 virtual ~VdbScalarGrid() = default;
341 900000 bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, const TType& vDatas) {
342
1/1
✓ Call 0 invoked.
900000 return VdbTree<TType, 1>::addVoxel(vX, vY, vZ, (void*)&vDatas, sizeof(TType), 1U);
343 }
344 };
345
346 typedef VdbScalarGrid<float> VdbFloatGrid;
347 template <>
348 10 inline std::string VdbFloatGrid::getTypeName() {
349
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
20 return "Tree_float_5_4_3";
350 }
351
352 typedef VdbScalarGrid<double> VdbDoubleGrid;
353 template <>
354 inline std::string VdbDoubleGrid::getTypeName() {
355 return "Tree_double_5_4_3";
356 }
357
358 template <typename TType>
359 class VdbVec3Grid : public VdbTree<TType, 3> {
360 protected:
361 std::string getTypeName() override {
362 std::cout << "getTypeName is not specialized for your Type" << std::endl;
363 assert(0);
364 return "";
365 }
366
367 public:
368
1/1
✓ Call 0 invoked.
10 VdbVec3Grid(const std::string& vName) : VdbTree<TType, 3>(vName) {
369 10 }
370
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
40 virtual ~VdbVec3Grid() = default;
371 900000 bool addVoxel(uint32_t vX, uint32_t vY, uint32_t vZ, const TType& v0, const TType& v1, const TType& v2) {
372
1/1
✓ Branch 1 taken 900000 times.
1/1
✓ Call 0 invoked.
900000 return VdbTree<TType, 3>::addVoxel(vX, vY, vZ, {v0, v1, v2});
373 }
374 };
375
376 typedef VdbVec3Grid<float> VdbVec3sGrid;
377 template <>
378 10 inline std::string VdbVec3sGrid::getTypeName() {
379
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
20 return "Tree_vec3s_5_4_3";
380 }
381
382 typedef VdbVec3Grid<double> VdbVec3dGrid;
383 template <>
384 inline std::string VdbVec3dGrid::getTypeName() {
385 return "Tree_vec3d_5_4_3";
386 }
387
388 typedef VdbVec3Grid<int32_t> VdbVec3iGrid;
389 template <>
390 inline std::string VdbVec3iGrid::getTypeName() {
391 return "Tree_vec3i_5_4_3";
392 }
393
394 typedef VdbVec3Grid<uint32_t> VdbVec3uiGrid;
395 template <>
396 inline std::string VdbVec3uiGrid::getTypeName() {
397 return "Tree_vec3ui_5_4_3";
398 }
399
400 typedef uint32_t KeyFrame;
401 typedef uint32_t LayerId;
402
403 class Writer {
404 private:
405 typedef std::unordered_map<LayerId, std::unique_ptr<ATree>> LayerContainer;
406 std::unordered_map<KeyFrame, LayerContainer> m_Trees;
407 KeyFrame m_CurrentKeyFrame = 0U;
408 FILE* m_File = nullptr;
409 int32_t m_LastError = 0;
410
411 public:
412 template <typename TTtree>
413 40 TTtree& getLayer(uint32_t vLayerId, const std::string& vLayerName) {
414
1/1
✓ Call 0 invoked.
40 auto& key = m_Trees[m_CurrentKeyFrame];
415
2/3
✓ Branch 2 taken 20 times.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
1/2
✓ Decision 'true' taken 40 times.
✗ Decision 'false' not taken.
3/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✗ Call 7 not invoked.
40 if (key.find(vLayerId) == key.end()) {
416
3/5
✓ Branch 1 taken 20 times.
✓ Branch 4 taken 20 times.
✓ Branch 8 taken 20 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
6/8
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 11 invoked.
✗ Call 12 not invoked.
✗ Call 15 not invoked.
40 key[vLayerId] = std::unique_ptr<TTtree>(new TTtree(vLayerName));
417 }
418
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
40 return static_cast<TTtree&>(*(key.at(vLayerId).get()));
419 }
420
421 10 Writer& setKeyFrame(uint32_t vKeyFrame) {
422 10 m_CurrentKeyFrame = vKeyFrame;
423 10 return *this;
424 }
425
426 1 Writer& save(const std::string& vFilePathName) {
427
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
1 if (!vFilePathName.empty()) {
428
1/1
✓ Call 0 invoked.
1 auto dot_p = vFilePathName.find_last_of('.');
429
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (dot_p != std::string::npos) {
430
1/1
✓ Branch 1 taken 1 times.
1/1
✓ Call 0 invoked.
1 auto base_file_path_name = vFilePathName.substr(0, dot_p);
431 1 size_t idx = 1;
432
2/2
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 1 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
11 for (auto& vdb : m_Trees) {
433
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 std::stringstream str;
434
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 10 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
10 if (m_Trees.size() > 1) {
435
5/5
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
✓ Branch 8 taken 10 times.
✓ Branch 13 taken 10 times.
✓ Branch 16 taken 10 times.
8/8
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
✓ Call 11 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
10 str << base_file_path_name << "_" << std::setfill('0') << std::setw(4) << idx++ << ".vdb"; // many frames
436 } else {
437
0/2
✗ Call 0 not invoked.
✗ Call 3 not invoked.
str << base_file_path_name << ".vdb";
438 }
439
3/4
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
1/2
✓ Decision 'true' taken 10 times.
✗ Decision 'false' not taken.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 9 not invoked.
10 if (openFileForWriting(str.str())) {
440
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 writeVdb(m_File, vdb.second);
441
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 closeFile();
442 } else {
443
0/6
✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 9 not invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
std::cout << "Error, cant write to the file " << str.str() << std::endl;
444 }
445
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
10 }
446
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
1 }
447 }
448 1 return *this;
449 }
450
451 // common grid types
452 10 VdbFloatGrid& getFloatLayer(uint32_t vLayerId, const std::string& vLayerName) {
453
1/1
✓ Call 0 invoked.
10 return getLayer<VdbFloatGrid>(vLayerId, vLayerName);
454 }
455 VdbDoubleGrid& getDoubleLayer(uint32_t vLayerId, const std::string& vLayerName) {
456 return getLayer<VdbDoubleGrid>(vLayerId, vLayerName);
457 }
458 10 VdbVec3sGrid& getVec3sLayer(uint32_t vLayerId, const std::string& vLayerName) {
459
1/1
✓ Call 0 invoked.
10 return getLayer<VdbVec3sGrid>(vLayerId, vLayerName);
460 }
461 VdbVec3dGrid& getVec3dLayer(uint32_t vLayerId, const std::string& vLayerName) {
462 return getLayer<VdbVec3dGrid>(vLayerId, vLayerName);
463 }
464 VdbVec3iGrid& getVec3iLayer(uint32_t vLayerId, const std::string& vLayerName) {
465 return getLayer<VdbVec3iGrid>(vLayerId, vLayerName);
466 }
467 VdbVec3uiGrid& getVec3uiLayer(uint32_t vLayerId, const std::string& vLayerName) {
468 return getLayer<VdbVec3uiGrid>(vLayerId, vLayerName);
469 }
470
471 private:
472 10 static void writeVdb(FILE* fp, const LayerContainer& vTrees) {
473 10 std::array<uint8_t, 8> header = {0x20, 0x42, 0x44, 0x56, 0x0, 0x0, 0x0, 0x0};
474
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
20 write_ptr(fp, header.data(), sizeof(uint8_t), header.size());
475
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 write_data<uint32_t>(fp, 224);
476
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 write_data<uint32_t>(fp, 8); // major openvdb 8
477
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 write_data<uint32_t>(fp, 1); // minor openvdb 8.1
478
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 write_data<uint8_t>(fp, 0);
479
2/2
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
10 write_string(fp, "00000000-0000-0000-0000-000000000000");
480
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 write_data<uint32_t>(fp, 0);
481
1/1
✓ Branch 2 taken 10 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10 write_data<uint32_t>(fp, (uint32_t)vTrees.size());
482
2/2
✓ Branch 5 taken 20 times.
✓ Branch 6 taken 10 times.
2/2
✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 10 times.
5/5
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
30 for (auto& tree : vTrees) {
483
1/1
✓ Branch 2 taken 20 times.
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
20 tree.second->write(fp);
484 }
485 10 }
486
487 10 bool openFileForWriting(const std::string& vFilePathName) {
488 #if _MSC_VER
489 m_LastError = fopen_s(&m_File, vFilePathName.c_str(), "wb");
490 #else
491
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
10 m_File = fopen(vFilePathName.c_str(), "wb");
492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 m_LastError = m_File ? 0 : errno;
493 #endif
494 10 return (m_LastError == 0);
495 }
496
497 10 void closeFile() {
498
1/1
✓ Call 0 invoked.
10 fclose(m_File);
499 10 }
500
501 long getFilePos() const {
502 return ftell(m_File);
503 }
504
505 void setFilePos(const long& vPos) {
506 fseek(m_File, vPos, SEEK_SET);
507 }
508 };
509
510 } // namespace vdb
511 } // namespace file
512 } // namespace ez
513

Directory: include/ezlibs/
File: ezStackString.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 96 97 99.0%
Functions: 46 46 100.0%
Branches: 43 51 84.3%
Decisions: 21 22 95.5%
Calls: 33 41 80.5%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 #include <cstring>
4 #include <stdexcept>
5 #include <type_traits>
6
7 namespace ez {
8
9 template <typename TChar, size_t StackChunkSize = 256, size_t HeapChunkSize = StackChunkSize>
10 class StackString {
11 static_assert(std::is_trivial<TChar>::value, "TChar must be a trivial type");
12
13 size_t _heapSize{}; // capacity allocated in _heapData
14 size_t _heapLength{}; // actual length used in _heapData
15 TChar* _heapData{}; // heap buffer (null if using stack)
16 size_t _stackLength{}; // actual length in _stackData
17 TChar _stackData[StackChunkSize + 1]{}; // stack buffer (+1 for null terminator)
18
19 public:
20 static constexpr size_t npos = static_cast<size_t>(-1);
21
22 public:
23 StackString() = default;
24
1/1
✓ Call 0 invoked.
22 explicit StackString(const TChar* str) { append(str); }
25
26
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
1 StackString(const StackString& other) { append(other.c_str()); }
27
28 1 StackString(StackString&& other) noexcept : _heapSize(other._heapSize), _heapLength(other._heapLength), _heapData(other._heapData), _stackLength(other._stackLength) {
29 1 std::memcpy(_stackData, other._stackData, sizeof(_stackData));
30 1 other._heapData = nullptr;
31 1 other._heapSize = 0;
32 1 other._heapLength = 0;
33 1 other._stackLength = 0;
34 1 other._stackData[0] = TChar(0);
35 1 }
36
37 StackString& operator=(const StackString& other) {
38 if (this != &other) {
39 clear();
40 append(other.c_str());
41 }
42 return *this;
43 }
44
45 StackString& operator=(StackString&& other) {
46 if (this != &other) {
47 clear();
48 delete[] _heapData;
49 _heapSize = other._heapSize;
50 _heapLength = other._heapLength;
51 _heapData = other._heapData;
52 _stackLength = other._stackLength;
53 std::memcpy(_stackData, other._stackData, sizeof(_stackData));
54 other._heapData = nullptr;
55 other._heapSize = 0;
56 other._heapLength = 0;
57 other._stackLength = 0;
58 other._stackData[0] = TChar(0);
59 }
60 return *this;
61 }
62
63
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
1/1
✓ Call 2 invoked.
26 ~StackString() { delete[] _heapData; }
64
65 1 void clear() {
66 1 _stackLength = 0;
67 1 _stackData[0] = TChar(0);
68
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/1
✓ Call 2 invoked.
1 delete[] _heapData;
69 1 _heapData = nullptr;
70 1 _heapSize = 0;
71 1 _heapLength = 0;
72 1 }
73
74 10 bool usingHeap() const { return _heapData != nullptr; }
75
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
36 const TChar* c_str() const { return _heapData ? _heapData : _stackData; }
76
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 32 times.
74 size_t size() const { return _heapData ? _heapLength : _stackLength; }
77
78 44 void reserve(size_t newSize) {
79 if (HeapChunkSize == 0) {
80
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
6 if (newSize > StackChunkSize) {
81
1/1
✓ Branch 2 taken 1 times.
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
2 throw std::runtime_error("Heap allocation disabled");
82 }
83 4 return;
84 }
85
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 18 times.
38 if (_heapData) {
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
2 if (newSize <= _heapSize) {
87 return;
88 }
89 2 size_t newCap = ((newSize / HeapChunkSize) + 1) * HeapChunkSize;
90
1/1
✓ Call 0 invoked.
2 TChar* newData = new TChar[newCap + 1];
91 2 std::memcpy(newData, _heapData, _heapLength * sizeof(TChar));
92 2 newData[_heapLength] = TChar(0);
93
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/1
✓ Call 2 invoked.
2 delete[] _heapData;
94 2 _heapData = newData;
95 2 _heapSize = newCap;
96 } else {
97
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 3 times.
36 if (newSize <= StackChunkSize) {
98 30 return;
99 }
100 6 size_t newCap = ((newSize / HeapChunkSize) + 1) * HeapChunkSize;
101
1/1
✓ Call 0 invoked.
6 _heapData = new TChar[newCap + 1];
102 6 std::memcpy(_heapData, _stackData, _stackLength * sizeof(TChar));
103 6 _heapLength = _stackLength;
104 6 _heapData[_heapLength] = TChar(0);
105 6 _heapSize = newCap;
106 }
107 }
108
109 44 void append(const TChar* str) {
110
1/1
✓ Call 0 invoked.
44 const size_t len = std::char_traits<TChar>::length(str);
111
1/1
✓ Call 0 invoked.
44 const size_t currentLen = size();
112 44 const size_t totalLen = currentLen + len;
113
1/1
✓ Call 0 invoked.
44 reserve(totalLen);
114
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 17 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 17 times.
42 if (_heapData) {
115 8 std::memcpy(_heapData + _heapLength, str, len * sizeof(TChar));
116 8 _heapLength += len;
117 8 _heapData[_heapLength] = TChar(0);
118 } else {
119 34 std::memcpy(_stackData + _stackLength, str, len * sizeof(TChar));
120 34 _stackLength += len;
121 34 _stackData[_stackLength] = TChar(0);
122 }
123 42 }
124
125 2 void append(TChar c) {
126 2 TChar tmp[2] = {c, TChar(0)};
127
1/1
✓ Branch 1 taken 2 times.
1/1
✓ Call 0 invoked.
2 append(tmp);
128 2 }
129
130 14 StackString& operator+=(const TChar* str) {
131
1/1
✓ Call 0 invoked.
14 append(str);
132 12 return *this;
133 }
134
135 1 StackString& operator+=(TChar c) {
136
1/1
✓ Call 0 invoked.
1 append(c);
137 1 return *this;
138 }
139
140 5 TChar& operator[](size_t index) {
141
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
5 if (index >= size()) {
142
1/1
✓ Branch 2 taken 2 times.
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
2 throw std::out_of_range("StackString index out of range");
143 }
144
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 return _heapData ? _heapData[index] : _stackData[index];
145 }
146
147 4 const TChar& at(size_t index) const {
148
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
1/1
✓ Call 0 invoked.
4 if (index >= size()) {
149
1/1
✓ Branch 2 taken 2 times.
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
2 throw std::out_of_range("StackString index out of range");
150 }
151
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 return _heapData ? _heapData[index] : _stackData[index];
152 }
153
154 4 size_t find(const TChar* needle, size_t pos = 0) const {
155
1/1
✓ Call 0 invoked.
4 const TChar* haystack = c_str();
156
1/1
✓ Call 0 invoked.
4 const size_t hayLen = size();
157
1/1
✓ Call 0 invoked.
4 const size_t needleLen = std::char_traits<TChar>::length(needle);
158
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3 times.
4 if (needleLen == 0 || pos > hayLen || needleLen > hayLen - pos) {
159 1 return npos;
160 }
161
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 22 times.
✓ Decision 'false' taken 1 times.
23 for (size_t i = pos; i <= hayLen - needleLen; ++i) {
162
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 20 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 20 times.
1/1
✓ Call 0 invoked.
22 if (std::char_traits<TChar>::compare(haystack + i, needle, needleLen) == 0) {
163 2 return i;
164 }
165 }
166 1 return npos;
167 }
168
169 2 StackString substr(size_t pos, size_t count = npos) const {
170
1/1
✓ Call 0 invoked.
2 const size_t len = size();
171
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (pos > len) {
172
1/1
✓ Branch 2 taken 1 times.
2/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
1 throw std::out_of_range("substr position out of range");
173 }
174
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 size_t actualCount = (count == npos || pos + count > len) ? len - pos : count;
175
1/1
✓ Call 0 invoked.
1 const TChar* src = c_str() + pos;
176
1/1
✓ Call 0 invoked.
1 TChar* tmp = new TChar[actualCount + 1];
177 1 std::memcpy(tmp, src, actualCount * sizeof(TChar));
178 1 tmp[actualCount] = TChar(0);
179
180
1/1
✓ Call 0 invoked.
1 StackString result(tmp);
181
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/1
✓ Call 2 invoked.
1 delete[] tmp;
182 1 return result;
183 }
184 };
185
186 } // namespace ez
187

Directory: include/ezlibs/
File: ezCmdProcessor.hpp
Date: 2025-07-28 14:06:36
Exec Total Coverage
Lines: 60 60 100.0%
Functions: 5 5 100.0%
Branches: 50 57 87.7%
Decisions: 25 32 78.1%
Calls: 67 75 89.3%
Line Branch Decision Call Exec Source
1 #pragma once
2
3 /*
4 MIT License
5
6 Copyright (c) 2014-2024 Stephane Cuillerdier (aka aiekick)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 */
26
27 // ezQuat is part of the ezLibs project : https://github.com/aiekick/ezLibs.git
28
29 #include <string>
30 #include <vector>
31 #include <functional>
32 #include <unordered_map>
33
34 namespace ez {
35 /*
36 this class will help process commands like serialize/deserialize operations
37 usually for :
38 - server/client communication
39 - undo/redo operation
40 - ..
41 */
42
43 class CmdProcessor {
44 public:
45 typedef std::string Command;
46 typedef std::string ProcessedCommand;
47 typedef std::vector<std::string> Arguments;
48 typedef std::function<void(const Command &, const Arguments &)> CmdFunctor;
49
50 private:
51 std::unordered_map<Command, CmdFunctor> m_cmdFunctors;
52
53 /* a processed commande will have this format : (space are not part of the process command, jsut for syntax clarity)
54 * COMMAND(DELIMITER ARG1 DELIMITER ARG2 DELIMITER ARG3)
55 *
56 * if not argument are sent :
57 * COMMAND()
58 *
59 * if one argument is sent :
60 * COMMAND(ARG1)
61 */
62
63 public:
64 /// <summary>
65 /// will encode a command ready to send
66 /// the encoding will fail if the delimiter exist in args words
67 /// </summary>
68 /// <param name="vCmd">the command</param>
69 /// <param name="vArgs">the command arguments</param>
70 /// <returns>the processed command</returns>
71 6 ProcessedCommand encode(const Command &vCmd, Arguments vArgs, char vDelimiter = ';') {
72
1/1
✓ Call 0 invoked.
6 ProcessedCommand ret;
73
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 6 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
6 if (!vCmd.empty()) {
74
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 5 times.
1/1
✓ Call 0 invoked.
6 if (vArgs.empty()) {
75 // no args
76
1/1
✓ Branch 1 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
1 ret = vCmd + "()";
77 } else {
78
1/1
✓ Branch 1 taken 5 times.
3/3
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
5 ret = vCmd + "(";
79 5 bool first = true;
80
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 4 times.
1/1
✓ Call 0 invoked.
5 if (vArgs.size() == 1U) {
81 // one args
82
1/1
✓ Branch 3 taken 1 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
1 ret += *vArgs.begin();
83 } else {
84
2/2
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 3 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 3 times.
4/4
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
15 for (const auto &arg: vArgs) {
85 // many args
86
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 11 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 11 times.
1/1
✓ Call 0 invoked.
12 if (arg.find(vDelimiter) != std::string::npos) {
87 // found
88
1/1
✓ Call 0 invoked.
1 return {};
89 }
90
2/2
✓ Branch 1 taken 11 times.
✓ Branch 4 taken 11 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
11 ret += vDelimiter + arg;
91
1/1
✓ Call 0 invoked.
11 first = false;
92 }
93 }
94
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 ret += ")";
95 }
96 } else {
97 #ifdef EZ_TOOLS_LOG
98 LogVarError("Err : the cmd is empty");
99 #endif // EZ_TOOLS_LOG
100 }
101
1/1
✓ Call 0 invoked.
5 return ret;
102
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
6 }
103
104 /// <summary>
105 /// will decode a command and call the registered functor
106 /// </summary>
107 /// <param name="vCmd"></param>
108 /// <returns>true is sucessfully decoded</returns>
109 10 bool decode(const ProcessedCommand &vCmd) {
110 10 bool ret = false;
111
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 10 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
10 if (!vCmd.empty()) {
112
1/1
✓ Call 0 invoked.
10 auto first_par = vCmd.find('(');
113
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 10 times.
✗ Decision 'false' not taken.
10 if (first_par != std::string::npos) {
114
1/1
✓ Branch 1 taken 10 times.
1/1
✓ Call 0 invoked.
10 const Command cmd = vCmd.substr(0, first_par);
115
1/1
✓ Call 0 invoked.
10 const auto end_par = vCmd.find(')', first_par);
116
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 10 times.
✗ Decision 'false' not taken.
10 if (end_par != std::string::npos) {
117
3/3
✓ Branch 2 taken 10 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 5 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 5 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
10 if (m_cmdFunctors.find(cmd) != m_cmdFunctors.end()) {
118
2/2
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
5 auto functor = m_cmdFunctors.at(cmd);
119
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
1/1
✓ Call 0 invoked.
5 if (functor != nullptr) {
120 // normally impossible to have null functor
121 5 ret = true;
122 5 ++first_par;
123
1/1
✓ Call 0 invoked.
5 Arguments args;
124
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 1 times.
5 if (first_par != end_par) {
125
1/1
✓ Branch 1 taken 4 times.
1/1
✓ Call 0 invoked.
4 char delimiter = vCmd.at(first_par);
126
1/1
✓ Call 0 invoked.
4 auto next_sep = vCmd.find(delimiter, first_par + 1);
127
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3 times.
4 if (next_sep == std::string::npos) {
128 // one arg
129
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
1 args.push_back(vCmd.substr(first_par, end_par - first_par));
130 } else {
131 // many args
132 3 size_t last_sep = first_par + 1; // we go after the delimiter
133 do {
134
2/2
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
8 args.push_back(vCmd.substr(last_sep, next_sep - last_sep));
135 8 last_sep = next_sep + 1;
136
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 3 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 3 times.
1/1
✓ Call 0 invoked.
8 } while ((next_sep = vCmd.find(delimiter, last_sep)) != std::string::npos);
137
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
3/4
✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
3 args.push_back(vCmd.substr(last_sep, end_par - last_sep));
138 }
139 }
140 // call functor
141
1/1
✓ Branch 1 taken 5 times.
1/1
✓ Call 0 invoked.
5 functor(cmd, args);
142
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
5 }
143
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
5 }
144 }
145
1/2
✓ Call 0 invoked.
✗ Call 1 not invoked.
10 }
146 }
147 10 return ret;
148 }
149
150 /// <summary>
151 /// will check is a commande is registered. si a functor is available for this command
152 /// </summary>
153 /// <param name="vCmd">the command to check</param>
154 /// <returns>true if registered</returns>
155
1/1
✓ Branch 2 taken 17 times.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
17 bool isCmdRegistered(const Command &vCmd) { return (m_cmdFunctors.find(vCmd) != m_cmdFunctors.end()); }
156
157 /// <summary>
158 /// will register a functor for a command
159 /// </summary>
160 /// <param name="vCmd">the commande to register</param>
161 /// <returns>true if successfully registered. false if command is empty or functor is null</returns>
162 7 bool registerCmd(const Command &vCmd, const CmdFunctor &vFunctor) {
163 7 bool ret = false;
164
6/6
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 2 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 2 times.
2/2
✓ Call 0 invoked.
✓ Call 3 invoked.
7 if (!vCmd.empty() && vFunctor != nullptr) {
165
2/3
✓ Branch 2 taken 5 times.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
1/2
✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
5 if (m_cmdFunctors.find(vCmd) == m_cmdFunctors.end()) {
166 // not found
167
2/2
✓ Call 0 invoked.
✓ Call 1 invoked.
5 m_cmdFunctors[vCmd] = vFunctor;
168 5 ret = true;
169 }
170 }
171 7 return ret;
172 }
173
174 /// <summary>
175 /// will unregister the command. the functor will be removed for this command
176 /// </summary>
177 /// <param name="vCmd">the commande to unregister</param>
178 /// <returns>true is successfully unregistered; false if the commande was not registered before</returns>
179 5 bool unRegisterCmd(const Command &vCmd) {
180 5 bool ret = false;
181
2/3
✓ Branch 2 taken 5 times.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
1/2
✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
3/3
✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
5 if (m_cmdFunctors.find(vCmd) != m_cmdFunctors.end()) {
182 // not found
183
1/1
✓ Call 0 invoked.
5 m_cmdFunctors.erase(vCmd);
184 5 ret = true;
185 }
186 5 return ret;
187 }
188 };
189 } // namespace ez
190