Overall list of functions
File | Lines | Functions | Branches | Decisions | Calls | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
ezAABBCC.hpp |
|
100.0% | 23 / 23 | 100.0% | 5 / 5 | -% | 0 / 0 | -% | 0 / 0 | 100.0% | 19 / 19 |
ezArgs.hpp |
|
86.3% | 202 / 234 | 96.0% | 24 / 25 | 72.1% | 194 / 269 | 75.4% | 95 / 126 | 64.6% | 250 / 387 |
ezBmp.hpp |
|
94.3% | 50 / 53 | 100.0% | 6 / 6 | 72.7% | 16 / 22 | 66.7% | 8 / 12 | 80.0% | 20 / 25 |
ezBuildInc.hpp |
|
97.7% | 128 / 131 | 100.0% | 18 / 18 | 93.9% | 154 / 164 | 77.3% | 34 / 44 | 85.4% | 204 / 239 |
ezCmdProcessor.hpp |
|
100.0% | 60 / 60 | 100.0% | 5 / 5 | 87.7% | 50 / 57 | 78.1% | 25 / 32 | 89.3% | 67 / 75 |
ezCnt.hpp |
|
92.9% | 13 / 14 | 100.0% | 6 / 6 | 80.0% | 4 / 5 | 75.0% | 3 / 4 | 100.0% | 12 / 12 |
ezCron.hpp |
|
95.4% | 267 / 280 | 100.0% | 25 / 25 | 92.1% | 234 / 254 | 91.7% | 132 / 144 | 82.2% | 244 / 297 |
ezExpr.hpp |
|
94.7% | 408 / 431 | 97.8% | 87 / 89 | 88.8% | 419 / 472 | 63.6% | 14 / 22 | 70.8% | 658 / 929 |
ezFigFont.hpp |
|
97.0% | 96 / 99 | 100.0% | 9 / 9 | 92.0% | 80 / 87 | 72.7% | 32 / 44 | 82.8% | 106 / 128 |
ezFile.hpp |
|
77.4% | 24 / 31 | 100.0% | 2 / 2 | 55.6% | 20 / 36 | 40.0% | 4 / 10 | 45.5% | 30 / 66 |
ezGif.hpp |
|
94.5% | 154 / 163 | 100.0% | 26 / 26 | 77.3% | 51 / 66 | 73.3% | 22 / 30 | 87.7% | 121 / 138 |
ezGL/uniforms.hpp |
|
95.7% | 135 / 141 | 100.0% | 6 / 6 | 72.6% | 146 / 201 | 80.0% | 16 / 20 | 80.0% | 168 / 210 |
ezGraph.hpp |
|
98.4% | 182 / 185 | 100.0% | 51 / 51 | 75.6% | 62 / 82 | 68.8% | 33 / 48 | 90.9% | 229 / 252 |
ezLog.hpp |
|
76.3% | 58 / 76 | 88.9% | 8 / 9 | 56.7% | 38 / 67 | 45.8% | 11 / 24 | 70.6% | 48 / 68 |
ezLzw.hpp |
|
96.6% | 57 / 59 | 100.0% | 10 / 10 | 92.3% | 48 / 52 | 91.7% | 11 / 12 | 83.2% | 79 / 95 |
ezMath.hpp |
|
100.0% | 70 / 70 | 100.0% | 79 / 79 | 100.0% | 24 / 24 | 100.0% | 6 / 6 | 96.7% | 29 / 30 |
ezNamedPipe.hpp |
|
87.9% | 51 / 58 | 100.0% | 12 / 12 | 69.7% | 23 / 33 | 68.2% | 15 / 22 | 91.5% | 43 / 47 |
ezStr.hpp |
|
79.4% | 50 / 63 | 91.7% | 11 / 12 | 59.2% | 29 / 49 | 63.6% | 14 / 22 | 72.1% | 31 / 43 |
ezSvg.hpp |
|
100.0% | 10 / 10 | 100.0% | 2 / 2 | 100.0% | 18 / 18 | 100.0% | 2 / 2 | 82.9% | 29 / 35 |
ezTime.hpp |
|
100.0% | 2 / 2 | 100.0% | 1 / 1 | 100.0% | 1 / 1 | -% | 0 / 0 | 100.0% | 4 / 4 |
ezVdbWriter.hpp |
|
97.6% | 243 / 249 | 96.8% | 60 / 62 | 81.0% | 128 / 158 | 76.5% | 26 / 34 | 85.0% | 216 / 254 |
ezVec2.hpp |
|
98.6% | 73 / 74 | 100.0% | 161 / 161 | 80.0% | 12 / 15 | 50.0% | 1 / 2 | 100.0% | 49 / 49 |
ezVec3.hpp |
|
98.3% | 58 / 59 | 100.0% | 143 / 143 | 71.8% | 28 / 39 | 50.0% | 1 / 2 | 87.2% | 41 / 47 |
ezVec4.hpp |
|
98.3% | 57 / 58 | 100.0% | 128 / 128 | 75.0% | 33 / 44 | 50.0% | 1 / 2 | 83.9% | 47 / 56 |
ezVoxWriter.hpp |
|
93.8% | 333 / 355 | 96.1% | 49 / 51 | 88.3% | 212 / 240 | 70.8% | 51 / 72 | 87.5% | 393 / 449 |
ezXml.hpp |
|
92.8% | 220 / 237 | 86.0% | 37 / 43 | 89.7% | 174 / 194 | 85.7% | 72 / 84 | 82.2% | 236 / 287 |
Directory: | include/ezlibs/ |
---|---|
File: | ezTime.hpp |
Date: | 2025-01-29 20:42:40 |
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 | } // namespace time | ||||
231 | } // namespace ez | ||||
232 |
Directory: | include/ezlibs/ |
---|---|
File: | ezExpr.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezStr.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 50 | 63 | 79.4% |
Functions: | 11 | 12 | 91.7% |
Branches: | 29 | 49 | 59.2% |
Decisions: | 14 | 22 | 63.6% |
Calls: | 31 | 43 | 72.1% |
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 | 31 | inline std::vector<std::string> splitStringToVector(const std::string& text, char delimiter, bool pushEmpty = false) { | |||
166 |
1/1✓ Call 0 invoked.
|
31 | std::vector<std::string> arr; | ||
167 |
1/2✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 31 times.
✗ Decision 'false' not taken.
|
1/1✓ Call 0 invoked.
|
31 | if (!text.empty()) { |
168 | 31 | std::string::size_type start = 0; | |||
169 |
1/1✓ Call 0 invoked.
|
31 | std::string::size_type end = text.find(delimiter, start); | ||
170 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 31 times.
|
2/2✓ Decision 'true' taken 19 times.
✓ Decision 'false' taken 31 times.
|
50 | while (end != std::string::npos) { | |
171 |
1/1✓ Branch 1 taken 19 times.
|
1/1✓ Call 0 invoked.
|
19 | std::string token = text.substr(start, end - start); | |
172 |
2/8✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 19 times.
✗ Branch 9 not taken.
|
1/2✓ Decision 'true' taken 19 times.
✗ Decision 'false' not taken.
|
1/2✓ Call 0 invoked.
✗ Call 3 not invoked.
|
19 | if (!token.empty() || (token.empty() && pushEmpty)) |
173 |
1/1✓ Branch 1 taken 19 times.
|
1/1✓ Call 0 invoked.
|
19 | arr.emplace_back(token); | |
174 | 19 | start = end + 1; | |||
175 |
1/1✓ Call 0 invoked.
|
19 | end = text.find(delimiter, start); | ||
176 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
19 | } | ||
177 |
1/1✓ Branch 1 taken 31 times.
|
1/1✓ Call 0 invoked.
|
31 | std::string token = text.substr(start); | |
178 |
2/8✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 31 times.
✗ Branch 9 not taken.
|
1/2✓ Decision 'true' taken 31 times.
✗ Decision 'false' not taken.
|
1/2✓ Call 0 invoked.
✗ Call 3 not invoked.
|
31 | 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.
|
31 | } | ||
181 | 31 | 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 | } // namespace ez | ||||
502 | } // namespace ez | ||||
503 | |||||
504 | //////////////////////////////////////////////////////////////////////////// | ||||
505 | //////////////////////////////////////////////////////////////////////////// | ||||
506 | //////////////////////////////////////////////////////////////////////////// | ||||
507 | |||||
508 | #ifdef _MSC_VER | ||||
509 | #pragma warning(pop) | ||||
510 | #elif defined(__GNUC__) || defined(__clang__) | ||||
511 | #pragma GCC diagnostic pop | ||||
512 | #endif | ||||
513 | |||||
514 | //////////////////////////////////////////////////////////////////////////// | ||||
515 | //////////////////////////////////////////////////////////////////////////// | ||||
516 | //////////////////////////////////////////////////////////////////////////// | ||||
517 |
Directory: | include/ezlibs/ |
---|---|
File: | ezLog.hpp |
Date: | 2025-01-29 20:42:40 |
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 | #include "ezStr.hpp" | ||||
36 | #include "ezTime.hpp" | ||||
37 | |||||
38 | #ifdef USE_GLFW3 | ||||
39 | #include <GLFW/glfw3.h> | ||||
40 | #elif defined(USE_SDL2) | ||||
41 | #include <SDL.h> | ||||
42 | #endif | ||||
43 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
44 | #include <tracy/Tracy.hpp> | ||||
45 | #endif | ||||
46 | |||||
47 | #ifdef _MSC_VER | ||||
48 | #include <Windows.h> | ||||
49 | #endif | ||||
50 | |||||
51 | #include <cstdarg> /* va_list, va_start, va_arg, va_end */ | ||||
52 | |||||
53 | #include <iostream> // std::cout | ||||
54 | |||||
55 | #include <mutex> | ||||
56 | #include <string> | ||||
57 | #include <vector> | ||||
58 | #include <memory> | ||||
59 | #include <cassert> | ||||
60 | #include <fstream> | ||||
61 | #include <stdexcept> | ||||
62 | #include <functional> | ||||
63 | using namespace std; | ||||
64 | |||||
65 | typedef long long int64; | ||||
66 | |||||
67 | #ifdef _MSC_VER | ||||
68 | #define __PRETTY_FUNCTION__ __FUNCSIG__ | ||||
69 | #endif | ||||
70 | |||||
71 | #define IsVerboseMode (ez::Log::Instance()->isVerboseMode() == true) | ||||
72 | |||||
73 | // #define LogVar(s, ...) ez::Log::Instance()->logStringWithFunction(std::string(__FUNCTION__), (int)(__LINE__), s, | ||||
74 | // ##__VA_ARGS__) | ||||
75 | |||||
76 | #define LogVarError(s, ...) \ | ||||
77 | ez::Log::Instance()->logStringByTypeWithFunction(ez::Log::LOGGING_MESSAGE_TYPE_ERROR, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__) | ||||
78 | |||||
79 | #define LogVarWarning(s, ...) \ | ||||
80 | ez::Log::Instance()->logStringByTypeWithFunction(ez::Log::LOGGING_MESSAGE_TYPE_WARNING, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__) | ||||
81 | |||||
82 | #define LogVarInfo(s, ...) \ | ||||
83 | ez::Log::Instance()->logStringByTypeWithFunction(ez::Log::LOGGING_MESSAGE_TYPE_INFOS, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__) | ||||
84 | |||||
85 | #define LogVarDebugError(s, ...) \ | ||||
86 | ez::Log::Instance()->logStringByTypeWithFunction_Debug(ez::Log::LOGGING_MESSAGE_TYPE_ERROR, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__) | ||||
87 | |||||
88 | #define LogVarDebugWarning(s, ...) \ | ||||
89 | ez::Log::Instance()->logStringByTypeWithFunction_Debug(ez::Log::LOGGING_MESSAGE_TYPE_WARNING, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__) | ||||
90 | |||||
91 | #define LogVarDebugInfo(s, ...) \ | ||||
92 | ez::Log::Instance()->logStringByTypeWithFunction_Debug(ez::Log::LOGGING_MESSAGE_TYPE_INFOS, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__) | ||||
93 | |||||
94 | #define LogVarLightError(s, ...) ez::Log::Instance()->logSimpleStringByType(ez::Log::LOGGING_MESSAGE_TYPE_ERROR, s, ##__VA_ARGS__) | ||||
95 | |||||
96 | #define LogVarLightWarning(s, ...) ez::Log::Instance()->logSimpleStringByType(ez::Log::LOGGING_MESSAGE_TYPE_WARNING, s, ##__VA_ARGS__) | ||||
97 | |||||
98 | #define LogVarLightInfo(s, ...) ez::Log::Instance()->logSimpleStringByType(ez::Log::LOGGING_MESSAGE_TYPE_INFOS, s, ##__VA_ARGS__) | ||||
99 | |||||
100 | #define LogVarTag(t, s, ...) ez::Log::Instance()->logStringByTypeWithFunction(t, std::string(__FUNCTION__), (int)(__LINE__), s, ##__VA_ARGS__) | ||||
101 | |||||
102 | #define LogVarLightTag(t, s, ...) ez::Log::Instance()->logSimpleStringByType(t, s, ##__VA_ARGS__) | ||||
103 | |||||
104 | #define LogAssert(a, b, ...) \ | ||||
105 | if (!(a)) { \ | ||||
106 | LogVarDebugInfo(b, ##__VA_ARGS__); \ | ||||
107 | assert(a); \ | ||||
108 | } | ||||
109 | |||||
110 | #ifdef USE_OPENGL | ||||
111 | #define LogGlError() ez::Log::Instance()->logGLError("" /*__FILE__*/, __FUNCTION__, __LINE__, "") | ||||
112 | #define LogGlErrorVar(var) ez::Log::Instance()->logGLError("" /*__FILE__*/, __FUNCTION__, __LINE__, var) | ||||
113 | #endif | ||||
114 | |||||
115 | namespace ez { | ||||
116 | |||||
117 | class Log { | ||||
118 | public: | ||||
119 | typedef int MessageType; | ||||
120 | typedef std::function<void(const int& vType, const std::string& vMessage)> LogMessageFunctor; | ||||
121 | enum MessageTypeEnum { LOGGING_MESSAGE_TYPE_INFOS = 0, LOGGING_MESSAGE_TYPE_WARNING, LOGGING_MESSAGE_TYPE_ERROR }; | ||||
122 | |||||
123 | protected: | ||||
124 | std::mutex m_logger_Mutex; | ||||
125 | |||||
126 | private: | ||||
127 | static size_t constexpr sMAX_BUFFER_SIZE = 1024U * 3U; | ||||
128 | ofstream m_debugLogFile; | ||||
129 | int64 m_lastTick = 0; | ||||
130 | bool m_reseted = false; | ||||
131 | LogMessageFunctor m_standardLogFunction; | ||||
132 | LogMessageFunctor m_openGLLogFunction; | ||||
133 | std::vector<std::string> m_messages; // file, function, line, msg | ||||
134 | bool m_consoleVerbose = false; | ||||
135 | |||||
136 | public: | ||||
137 |
5/5✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
58 | Log() { | ||
138 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
139 | ZoneScoped; | ||||
140 | #endif | ||||
141 | 58 | } | |||
142 | 58 | ~Log() { | |||
143 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
144 | ZoneScoped; | ||||
145 | #endif | ||||
146 |
1/1✓ Call 0 invoked.
|
58 | close(); | ||
147 |
4/4✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
|
58 | } | ||
148 | void logSimpleString(const char* fmt, ...) { | ||||
149 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
150 | ZoneScoped; | ||||
151 | #endif | ||||
152 | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||||
153 | lck.lock(); | ||||
154 | va_list args; | ||||
155 | va_start(args, fmt); | ||||
156 | m_LogString(nullptr, nullptr, nullptr, fmt, args); | ||||
157 | va_end(args); | ||||
158 | lck.unlock(); | ||||
159 | } | ||||
160 | ✗ | void logSimpleStringByType(const MessageType& vType, const char* fmt, ...) { | |||
161 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
162 | ZoneScoped; | ||||
163 | #endif | ||||
164 |
0/1✗ Call 0 not invoked.
|
✗ | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||
165 |
0/1✗ Call 0 not invoked.
|
✗ | lck.lock(); | ||
166 | va_list args; | ||||
167 | ✗ | va_start(args, fmt); | |||
168 |
0/1✗ Call 0 not invoked.
|
✗ | m_LogString(&vType, nullptr, nullptr, fmt, args); | ||
169 | ✗ | va_end(args); | |||
170 |
0/1✗ Call 0 not invoked.
|
✗ | lck.unlock(); | ||
171 | } | ||||
172 | void logStringWithFunction(const std::string& vFunction, const int& vLine, const char* fmt, ...) { | ||||
173 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
174 | ZoneScoped; | ||||
175 | #endif | ||||
176 | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||||
177 | lck.lock(); | ||||
178 | va_list args; | ||||
179 | va_start(args, fmt); | ||||
180 | m_LogString(nullptr, &vFunction, &vLine, fmt, args); | ||||
181 | va_end(args); | ||||
182 | lck.unlock(); | ||||
183 | } | ||||
184 | 80 | void logStringByTypeWithFunction(const MessageType& vType, const std::string& vFunction, const int& vLine, const char* fmt, ...) { | |||
185 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
186 | ZoneScoped; | ||||
187 | #endif | ||||
188 |
1/1✓ Call 0 invoked.
|
80 | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||
189 |
1/1✓ Branch 1 taken 80 times.
|
1/1✓ Call 0 invoked.
|
80 | lck.lock(); | |
190 | va_list args; | ||||
191 | 80 | va_start(args, fmt); | |||
192 |
1/1✓ Branch 1 taken 80 times.
|
1/1✓ Call 0 invoked.
|
80 | m_LogString(&vType, &vFunction, &vLine, fmt, args); | |
193 | 80 | va_end(args); | |||
194 |
1/1✓ Branch 1 taken 80 times.
|
1/1✓ Call 0 invoked.
|
80 | lck.unlock(); | |
195 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
80 | } | ||
196 | void logStringByTypeWithFunction_Debug(const MessageType& vType, const std::string& vFunction, const int& vLine, const char* fmt, ...) { | ||||
197 | #ifdef _DEBUG | ||||
198 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
199 | ZoneScoped; | ||||
200 | #endif | ||||
201 | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||||
202 | lck.lock(); | ||||
203 | va_list args; | ||||
204 | va_start(args, fmt); | ||||
205 | m_LogString(&vType, &vFunction, &vLine, fmt, args); | ||||
206 | va_end(args); | ||||
207 | lck.unlock(); | ||||
208 | #else | ||||
209 | (void)vType; | ||||
210 | (void)vFunction; | ||||
211 | (void)vLine; | ||||
212 | (void)fmt; | ||||
213 | #endif | ||||
214 | } | ||||
215 | void logStringWithFunction_Debug(const std::string& vFunction, const int& vLine, const char* fmt, ...) { | ||||
216 | #ifdef _DEBUG | ||||
217 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
218 | ZoneScoped; | ||||
219 | #endif | ||||
220 | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||||
221 | lck.lock(); | ||||
222 | va_list args; | ||||
223 | va_start(args, fmt); | ||||
224 | m_LogString(nullptr, &vFunction, &vLine, fmt, args); | ||||
225 | va_end(args); | ||||
226 | lck.unlock(); | ||||
227 | #else | ||||
228 | (void)vFunction; | ||||
229 | (void)vLine; | ||||
230 | (void)fmt; | ||||
231 | #endif | ||||
232 | } | ||||
233 | #ifdef USE_OPENGL | ||||
234 | bool logGLError(const std::string& vFile, const std::string& vFunc, int vLine, const std::string& vGLFunc = "") const { | ||||
235 | (void)vFile; | ||||
236 | |||||
237 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
238 | ZoneScoped; | ||||
239 | #endif | ||||
240 | if (!ez::Log::Instance()->ConsoleVerbose) | ||||
241 | return false; | ||||
242 | |||||
243 | const GLenum err(glGetError()); | ||||
244 | if (err != GL_NO_ERROR) { | ||||
245 | std::string error; | ||||
246 | |||||
247 | switch (err) { | ||||
248 | case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break; | ||||
249 | case GL_INVALID_ENUM: error = "INVALID_ENUM"; break; | ||||
250 | case GL_INVALID_VALUE: error = "INVALID_VALUE"; break; | ||||
251 | case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break; | ||||
252 | case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break; | ||||
253 | case GL_STACK_UNDERFLOW: error = "GL_STACK_UNDERFLOW"; break; | ||||
254 | case GL_STACK_OVERFLOW: error = "GL_STACK_OVERFLOW"; break; | ||||
255 | } | ||||
256 | |||||
257 | if (!error.empty()) { | ||||
258 | const int64 ticks = ez::time::GetTicks(); | ||||
259 | const float time = (ticks - m_lastTick) / 1000.0f; | ||||
260 | |||||
261 | std::string msg; | ||||
262 | |||||
263 | if (!vGLFunc.empty()) { | ||||
264 | #ifdef USE_GLFW3 | ||||
265 | msg = str::toStr( | ||||
266 | "[%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()); | ||||
267 | #elif defined(USE_SDL2) | ||||
268 | msg = str::toStr( | ||||
269 | "[%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()); | ||||
270 | #endif | ||||
271 | } else { | ||||
272 | #ifdef USE_GLFW3 | ||||
273 | msg = str::toStr("[%010.3fs][GLFW3 0x%X][%s:%i] %s\n", time, (uintptr_t)glfwGetCurrentContext(), vFunc.c_str(), vLine, error.c_str()); | ||||
274 | #elif defined(USE_SDL2) | ||||
275 | 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()); | ||||
276 | #endif | ||||
277 | } | ||||
278 | |||||
279 | LogVarLightError("%s", msg.c_str()); | ||||
280 | |||||
281 | if (m_openGLLogFunction != nullptr) { | ||||
282 | auto arr = str::splitStringToVector(msg, '\n'); | ||||
283 | if (arr.size() == 1U) { | ||||
284 | m_openGLLogFunction(2, msg); | ||||
285 | } else { | ||||
286 | for (auto m : arr) { | ||||
287 | m_openGLLogFunction(2, m); | ||||
288 | } | ||||
289 | } | ||||
290 | } | ||||
291 | |||||
292 | if (!m_debugLogFile.bad()) | ||||
293 | m_debugLogFile << msg << std::endl; | ||||
294 | |||||
295 | return true; | ||||
296 | } | ||||
297 | } | ||||
298 | |||||
299 | return false; | ||||
300 | } | ||||
301 | #endif | ||||
302 | 58 | void close() { | |||
303 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
304 | ZoneScoped; | ||||
305 | #endif | ||||
306 |
1/1✓ Call 0 invoked.
|
58 | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||
307 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | lck.lock(); | |
308 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | m_debugLogFile.close(); | |
309 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | m_debugLogFile.clear(); | |
310 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | lck.unlock(); | |
311 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
58 | } | ||
312 | |||||
313 | std::string getLastErrorAsString() { | ||||
314 | std::string msg; | ||||
315 | |||||
316 | #ifdef _MSC_VER | ||||
317 | // Get the error message, if any. | ||||
318 | const DWORD errorMessageID = ::GetLastError(); | ||||
319 | if (errorMessageID == 0 || errorMessageID == 6) | ||||
320 | return std::string(); // No error message has been recorded | ||||
321 | |||||
322 | LPSTR messageBuffer = nullptr; | ||||
323 | const size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
324 | nullptr, | ||||
325 | errorMessageID, | ||||
326 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
327 | (LPSTR)&messageBuffer, | ||||
328 | 0, | ||||
329 | nullptr); | ||||
330 | |||||
331 | msg = std::string(messageBuffer, size); | ||||
332 | |||||
333 | // Free the buffer. | ||||
334 | LocalFree(messageBuffer); | ||||
335 | #else | ||||
336 | // cAssert(0, "to implement"); | ||||
337 | #endif | ||||
338 | return msg; | ||||
339 | } | ||||
340 | |||||
341 | void setStandardLogMessageFunctor(const LogMessageFunctor& vMessageLogFunctor) { m_standardLogFunction = vMessageLogFunctor; } | ||||
342 | void setOpenglLogMessageFunctor(const LogMessageFunctor& vMessageLogFunctor) { m_openGLLogFunction = vMessageLogFunctor; } | ||||
343 | |||||
344 | void setVerboseMode(bool vFlag) { m_consoleVerbose = vFlag; } | ||||
345 | bool isVerboseMode() { return m_consoleVerbose; } | ||||
346 | |||||
347 | private: | ||||
348 | 80 | void m_createFileOnDisk() { | |||
349 |
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) { | |
350 | 22 | return; | |||
351 | } | ||||
352 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
353 | ZoneScoped; | ||||
354 | #endif | ||||
355 |
1/1✓ Call 0 invoked.
|
58 | std::unique_lock<std::mutex> lck(ez::Log::m_logger_Mutex, std::defer_lock); | ||
356 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | lck.lock(); | |
357 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | m_debugLogFile.open("debug.log", ios::out); | |
358 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | m_lastTick = time::getTicks(); | |
359 | 58 | m_consoleVerbose = false; | |||
360 | 58 | m_reseted = true; | |||
361 |
1/1✓ Branch 1 taken 58 times.
|
1/1✓ Call 0 invoked.
|
58 | lck.unlock(); | |
362 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
58 | } | ||
363 | |||||
364 | private: | ||||
365 | 69 | void m_LogString(const MessageType* vType, const std::string* vFunction, const int* vLine, const char* vStr) { | |||
366 |
1/1✓ Call 0 invoked.
|
69 | const int64 ticks = time::getTicks(); | ||
367 | 69 | const double time = (ticks - m_lastTick) / 1000.0; | |||
368 | |||||
369 | static char TempBufferBis[sMAX_BUFFER_SIZE + 1]; | ||||
370 | 69 | int w = 0; | |||
371 |
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) | |
372 |
1/1✓ Call 0 invoked.
|
69 | w = snprintf(TempBufferBis, sMAX_BUFFER_SIZE, "[%010.3fs][%s:%i] %s", time, vFunction->c_str(), *vLine, vStr); | ||
373 | else | ||||
374 | ✗ | w = snprintf(TempBufferBis, sMAX_BUFFER_SIZE, "[%010.3fs] %s", time, vStr); | |||
375 |
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) { | |
376 |
1/1✓ Branch 1 taken 69 times.
|
1/1✓ Call 0 invoked.
|
69 | const std::string msg = std::string(TempBufferBis, (size_t)w); | |
377 | |||||
378 |
1/1✓ Branch 1 taken 69 times.
|
1/1✓ Call 0 invoked.
|
69 | m_messages.push_back(msg); | |
379 | |||||
380 | #if defined(TRACY_ENABLE) && defined(LOG_TRACY_MESSAGES) | ||||
381 | TracyMessageL(m_messages[m_messages.size() - 1U].c_str()); | ||||
382 | #endif | ||||
383 | |||||
384 |
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; | |
385 | |||||
386 |
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) { |
387 | ✗ | int type = 0; | |||
388 | |||||
389 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (vType) { | ||
390 | ✗ | type = (int)(*vType); | |||
391 | } | ||||
392 | |||||
393 |
0/1✗ Call 0 not invoked.
|
✗ | auto arr = str::splitStringToVector(msg, '\n'); | ||
394 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
0/1✗ Call 0 not invoked.
|
✗ | if (arr.size() == 1U) { | |
395 |
0/1✗ Call 0 not invoked.
|
✗ | m_standardLogFunction(type, msg); | ||
396 | } else { | ||||
397 |
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) { | |
398 |
0/1✗ Call 0 not invoked.
|
✗ | m_standardLogFunction(type, m); | ||
399 | } | ||||
400 | } | ||||
401 | } | ||||
402 | |||||
403 |
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()) |
404 |
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; | |
405 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
69 | } | ||
406 | 69 | } | |||
407 | 80 | void m_LogString(const MessageType* vType, const std::string* vFunction, const int* vLine, const char* fmt, va_list vArgs) { | |||
408 | static char TempBuffer[sMAX_BUFFER_SIZE + 1]; | ||||
409 | 80 | int w = vsnprintf(TempBuffer, sMAX_BUFFER_SIZE, fmt, vArgs); | |||
410 |
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) { | |
411 |
1/1✓ Call 0 invoked.
|
69 | m_LogString(vType, vFunction, vLine, TempBuffer); | ||
412 | } | ||||
413 | 80 | } | |||
414 | |||||
415 | public: | ||||
416 | 80 | static ez::Log* Instance(ez::Log* vCopyPtr = nullptr, bool vForce = false) { | |||
417 |
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 | |
418 | static ez::Log* _instance_copy = nullptr; | ||||
419 |
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) { | |
420 | ✗ | _instance_copy = vCopyPtr; | |||
421 |
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) { | |
422 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
80 | instance_ptr->m_createFileOnDisk(); | ||
423 | } | ||||
424 |
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) { | |
425 | ✗ | return _instance_copy; | |||
426 | } | ||||
427 |
1/1✓ Call 0 invoked.
|
80 | return instance_ptr.get(); | ||
428 | } | ||||
429 | }; | ||||
430 | |||||
431 | } // namespace ez | ||||
432 |
Directory: | include/ezlibs/ |
---|---|
File: | ezFigFont.hpp |
Date: | 2025-01-29 20:42:40 |
Warnings: | 4 unchecked decisions! |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 96 | 99 | 97.0% |
Functions: | 9 | 9 | 100.0% |
Branches: | 80 | 87 | 92.0% |
Decisions: | 32 | 44 | 72.7% |
Calls: | 106 | 128 | 82.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 | // 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::string line; | ||
138 |
1/1✓ Call 0 invoked.
|
512 | std::vector<std::string> asciiArt; | ||
139 |
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) { | |
140 | 190 | cChar = idx + baseChar; | |||
141 |
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)) { |
142 | // return false; | ||||
143 | } | ||||
144 |
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) { | |
145 |
1/1✓ Branch 1 taken 14 times.
|
1/1✓ Call 0 invoked.
|
14 | cChar = additionnal_chars.at(idx - required_chars_count); | |
146 |
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)) { |
147 | // return false; | ||||
148 | } | ||||
149 | } else { | ||||
150 |
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)) { |
151 | // return false; | ||||
152 | } | ||||
153 | } | ||||
154 | 512 | ++idx; | |||
155 |
2/4✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
512 | } | ||
156 | 2 | return true; | |||
157 |
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 | } | ||
158 | |||||
159 | 512 | bool m_parseChar(std::ifstream& vFile, const size_t vChar) { | |||
160 |
1/1✓ Call 0 invoked.
|
512 | std::string row; | ||
161 | 512 | size_t charCode = vChar; | |||
162 |
1/1✓ Call 0 invoked.
|
512 | Glyph glyph; | ||
163 |
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) { | |
164 |
1/1✓ Branch 1 taken 308 times.
|
1/1✓ Call 0 invoked.
|
308 | std::getline(vFile, row); | |
165 |
1/1✓ Call 0 invoked.
|
308 | size_t spacePos = row.find(' '); | ||
166 |
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) { | |
167 |
1/1✓ Branch 1 taken 306 times.
|
1/1✓ Call 0 invoked.
|
306 | const auto numStr = row.substr(0, spacePos); | |
168 |
1/1✓ Branch 1 taken 306 times.
|
1/1✓ Call 0 invoked.
|
306 | const auto descStr = row.substr(spacePos + 1); | |
169 |
1/1✓ Branch 1 taken 306 times.
|
1/1✓ Call 0 invoked.
|
306 | charCode = static_cast<size_t>(std::stoi(numStr)); | |
170 |
2/4✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
306 | } else { | ||
171 | 2 | return false; | |||
172 | } | ||||
173 | } | ||||
174 |
1/1✓ Branch 1 taken 510 times.
|
1/1✓ Call 0 invoked.
|
510 | glyph.rows.reserve(m_header.height); | |
175 |
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) { | |
176 |
1/1✓ Branch 1 taken 4080 times.
|
1/1✓ Call 0 invoked.
|
4080 | std::getline(vFile, row); | |
177 |
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()) { |
178 |
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() == '@') { |
179 |
1/1✓ Call 0 invoked.
|
4590 | row.pop_back(); | ||
180 | } | ||||
181 |
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() == ' ') { |
182 |
1/1✓ Branch 1 taken 4072 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
4072 | row = row.substr(1); | |
183 | } | ||||
184 |
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) { |
185 |
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)) { | |
186 | 164 | c = ' '; | |||
187 | } | ||||
188 | } | ||||
189 | } | ||||
190 |
1/1✓ Branch 1 taken 4080 times.
|
1/1✓ Call 0 invoked.
|
4080 | glyph.rows.push_back(row); | |
191 | } | ||||
192 |
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; | |
193 | 510 | return true; | |||
194 |
2/4✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
512 | } | ||
195 | |||||
196 | 5 | std::string m_printString(const std::string& vPattern) { | |||
197 |
1/1✓ Branch 1 taken 5 times.
|
1/1✓ Call 0 invoked.
|
5 | std::stringstream ret; | |
198 |
1/1✓ Call 0 invoked.
|
5 | std::vector<std::string> rows; | ||
199 |
1/1✓ Branch 1 taken 5 times.
|
1/1✓ Call 0 invoked.
|
5 | rows.resize(m_header.height); | |
200 | 5 | size_t row_idx = 0; | |||
201 |
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) { |
202 |
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) { |
203 |
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); | |
204 | } | ||||
205 | 40 | ++row_idx; | |||
206 | // remove empty rows | ||||
207 |
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) { |
208 |
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; | |
209 | } | ||||
210 | } | ||||
211 |
1/1✓ Branch 1 taken 5 times.
|
1/1✓ Call 0 invoked.
|
10 | return ret.str(); | |
212 |
2/4✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
5 | } | ||
213 | |||||
214 | 448 | std::string m_getCharRow(size_t vC, size_t vRowIdx) { | |||
215 |
1/1✓ Branch 1 taken 448 times.
|
1/1✓ Call 0 invoked.
|
448 | auto it = m_glyphs.find(vC); | |
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 (it != m_glyphs.end()) { |
217 |
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()) { |
218 |
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); | |
219 | } | ||||
220 | } | ||||
221 |
0/1✗ Call 0 not invoked.
|
✗ | return {}; | ||
222 | } | ||||
223 | }; | ||||
224 | |||||
225 | } | ||||
226 |
Directory: | include/ezlibs/ |
---|---|
File: | ezVec2.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 73 | 74 | 98.6% |
Functions: | 161 | 161 | 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 | 1 | 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 | } // namespace ez | ||||
566 |
Directory: | include/ezlibs/ |
---|---|
File: | ezSvg.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 10 | 10 | 100.0% |
Functions: | 2 | 2 | 100.0% |
Branches: | 18 | 18 | 100.0% |
Decisions: | 2 | 2 | 100.0% |
Calls: | 29 | 35 | 82.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 | // ezSvg is part of the ezLibs project : https://github.com/aiekick/ezLibs.git | ||||
28 | |||||
29 | /* | ||||
30 | #include "ezsvg.h" | ||||
31 | #include <iostream> | ||||
32 | |||||
33 | int main() { | ||||
34 | ez::SVG svg("1024", "768"); | ||||
35 | |||||
36 | // Ajouter un d�grad� lin�aire | ||||
37 | svg.addLinearGradient("gradient1", { | ||||
38 | {"rgba(255,0,0,1)", 0.0}, | ||||
39 | {"rgba(0,255,0,1)", 0.5}, | ||||
40 | {"rgba(0,0,255,1)", 1.0} | ||||
41 | }); | ||||
42 | |||||
43 | // Ajouter un rectangle avec un d�grad� | ||||
44 | svg.addRectangleWithGradient(50, 50, 300, 150, "gradient1"); | ||||
45 | |||||
46 | // Ajouter un cercle avec une couleur RGBA | ||||
47 | svg.addCircle(500, 200, 50, "rgba(0,0,255,0.5)", "rgba(255,0,0,0.8)", 3); | ||||
48 | |||||
49 | // Exporter le fichier SVG | ||||
50 | try { | ||||
51 | svg.exportToFile("output_with_gradient.svg"); | ||||
52 | std::cout << "SVG exported successfully to 'output_with_gradient.svg'" << std::endl; | ||||
53 | } catch (const std::exception& e) { | ||||
54 | std::cerr << e.what() << std::endl; | ||||
55 | } | ||||
56 | |||||
57 | return 0; | ||||
58 | } | ||||
59 | |||||
60 | */ | ||||
61 | |||||
62 | #include <string> | ||||
63 | #include <vector> | ||||
64 | #include <fstream> | ||||
65 | #include <sstream> | ||||
66 | |||||
67 | #include "ezMath.hpp" | ||||
68 | #include "ezXml.hpp" | ||||
69 | |||||
70 | namespace ez { | ||||
71 | namespace img { | ||||
72 | |||||
73 | class Svg { | ||||
74 | private: | ||||
75 | ez::uvec2 m_size{800U}; | ||||
76 | std::vector<ez::xml::Node> m_elements; | ||||
77 | std::vector<ez::xml::Node> m_gradients; | ||||
78 | |||||
79 | public: | ||||
80 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | Svg(const ez::uvec2 &vSize = 800U) : m_size(vSize) {} | ||
81 | |||||
82 | void addRectangle( // | ||||
83 | const ez::uvec2 &vMin, | ||||
84 | const ez::uvec2 &vMax, | ||||
85 | const std::string &fillColor = "none", | ||||
86 | const std::string &strokeColor = "black", | ||||
87 | int strokeWidth = 1) { | ||||
88 | ez::xml::Node node("rect"); // | ||||
89 | node.addAttribute("x", vMin.x) // | ||||
90 | .addAttribute("y", vMin.y) // | ||||
91 | .addAttribute("width", vMax.x) // | ||||
92 | .addAttribute("height", vMax.y) | ||||
93 | .addAttribute("style", m_generateStyle(fillColor, strokeColor, strokeWidth)); | ||||
94 | m_elements.push_back(node); | ||||
95 | } | ||||
96 | |||||
97 | void addText( // | ||||
98 | const ez::uvec2 &vPos, | ||||
99 | const std::string &text, | ||||
100 | const std::string &color = "black", | ||||
101 | int32_t fontSize = 16) { | ||||
102 | ez::xml::Node node("text"); | ||||
103 | node.addAttribute("x", vPos.x) // | ||||
104 | .addAttribute("y", vPos.y) // | ||||
105 | .addAttribute("fill", color) // | ||||
106 | .addAttribute("font-size", fontSize) // | ||||
107 | .setContent(text); | ||||
108 | m_elements.push_back(node); | ||||
109 | } | ||||
110 | |||||
111 | void addCircle( // | ||||
112 | const ez::uvec2 &vPos, | ||||
113 | int32_t vRadius, | ||||
114 | const std::string &fillColor = "none", | ||||
115 | const std::string &strokeColor = "black", | ||||
116 | int32_t strokeWidth = 1) { | ||||
117 | ez::xml::Node node("circle"); | ||||
118 | node.addAttribute("cx", vPos.x) // | ||||
119 | .addAttribute("cy", vPos.y) // | ||||
120 | .addAttribute("r", vRadius) // | ||||
121 | .addAttribute("style", m_generateStyle(fillColor, strokeColor, strokeWidth)); | ||||
122 | m_elements.push_back(node); | ||||
123 | } | ||||
124 | |||||
125 | void addLine( // | ||||
126 | const ez::uvec2 &vPos1, // | ||||
127 | const ez::uvec2 &vPos2, // | ||||
128 | const std::string &strokeColor = "black", | ||||
129 | int32_t strokeWidth = 1) { | ||||
130 | ez::xml::Node node("line"); | ||||
131 | node.addAttribute("x1", vPos1.x) // | ||||
132 | .addAttribute("y1", vPos1.y) // | ||||
133 | .addAttribute("x2", vPos2.x) // | ||||
134 | .addAttribute("y2", vPos2.y) // | ||||
135 | .addAttribute("style", m_generateStyle(strokeColor, strokeWidth)); | ||||
136 | m_elements.push_back(node); | ||||
137 | } | ||||
138 | |||||
139 | 1 | void addLinearGradient( // | |||
140 | const std::string &id, | ||||
141 | const std::vector<std::pair<std::string, float>> &stops) { | ||||
142 |
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.
|
2 | ez::xml::Node node("linearGradient"); | |
143 |
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 | node.addAttribute("id", id); | |
144 |
2/2✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
|
4/4✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
|
2 | for (const auto &stop: stops) { |
145 |
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.
|
2 | auto &stopNode = node.addChild("stop"); | |
146 |
5/5✓ 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.
|
6/7✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 15 invoked.
✗ Call 16 not invoked.
|
2 | stopNode.addAttribute("style") << "stop-color:" << stop.first << "%"; | |
147 |
4/4✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
|
6/7✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 12 invoked.
✓ Call 13 invoked.
✗ Call 14 not invoked.
|
2 | stopNode.addAttribute("offset") << stop.second * 100.0f << "%"; | |
148 | } | ||||
149 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_gradients.push_back(node); | |
150 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
1 | } | ||
151 | |||||
152 | // Utiliser un d�grad� dans les formes | ||||
153 | void addRectangleWithGradient(// | ||||
154 | const ez::uvec2 &vMin, | ||||
155 | const ez::uvec2 &vMax, | ||||
156 | const std::string &gradientId, | ||||
157 | const std::string &strokeColor = "black", | ||||
158 | int32_t strokeWidth = 1) { | ||||
159 | ez::xml::Node node("rect"); // | ||||
160 | node.addAttribute("x", vMin.x) // | ||||
161 | .addAttribute("y", vMin.y) // | ||||
162 | .addAttribute("width", vMax.x) // | ||||
163 | .addAttribute("height", vMax.y) | ||||
164 | .addAttribute("style", | ||||
165 | m_generateStyle("url(#" + gradientId + ")", strokeColor, strokeWidth)); // | ||||
166 | m_elements.push_back(node); | ||||
167 | } | ||||
168 | |||||
169 | void exportToFile(const std::string &filename) { | ||||
170 | std::ofstream file(filename); | ||||
171 | if (file.is_open()) { | ||||
172 | ez::xml::Node node("svg"); | ||||
173 | node.addAttribute("xmlns", "http://www.w3.org/2000/svg") // | ||||
174 | .addAttribute("width", m_size.x) // | ||||
175 | .addAttribute("height", m_size.y); | ||||
176 | |||||
177 | // Ajouter les d�grad�s | ||||
178 | if (!m_gradients.empty()) { | ||||
179 | auto &defs_node = node.addChild("defs"); | ||||
180 | for (const auto &gradient_node: m_gradients) { | ||||
181 | defs_node.addChild(gradient_node); | ||||
182 | } | ||||
183 | } | ||||
184 | |||||
185 | // Ajouter les �l�ments | ||||
186 | for (const auto &elem_node: m_elements) { | ||||
187 | node.addChild(elem_node); | ||||
188 | } | ||||
189 | |||||
190 | file << node.dump(); | ||||
191 | |||||
192 | file.close(); | ||||
193 | } | ||||
194 | } | ||||
195 | |||||
196 | private: | ||||
197 | std::string m_generateStyle(const std::string &strokeColor, int strokeWidth) { | ||||
198 | std::ostringstream style; | ||||
199 | style << "stroke:" << strokeColor << ";" | ||||
200 | << "stroke-width:" << strokeWidth << ";"; | ||||
201 | return style.str(); | ||||
202 | } | ||||
203 | |||||
204 | std::string m_generateStyle(const std::string &fillColor, const std::string &strokeColor, int strokeWidth) { | ||||
205 | std::ostringstream style; | ||||
206 | style << "fill:" << fillColor << ";" | ||||
207 | << "stroke:" << strokeColor << ";" | ||||
208 | << "stroke-width:" << strokeWidth << ";"; | ||||
209 | return style.str(); | ||||
210 | } | ||||
211 | }; | ||||
212 | |||||
213 | } // namespace img | ||||
214 | } // namespace ez | ||||
215 |
Directory: | include/ezlibs/ |
---|---|
File: | ezXml.hpp |
Date: | 2025-01-29 20:42:40 |
Warnings: | 1 unchecked decisions! |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 220 | 237 | 92.8% |
Functions: | 37 | 43 | 86.0% |
Branches: | 174 | 194 | 89.7% |
Decisions: | 72 | 84 | 85.7% |
Calls: | 236 | 287 | 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 | // 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.
|
17 | Attribute() = default; | ||
64 | |||||
65 |
1/1✓ Call 0 invoked.
|
13 | explicit Attribute(const std::string &vValue) : m_value(vValue) {} | ||
66 | |||||
67 | template<typename T> | ||||
68 | 10 | Attribute &operator<<(const T &vValue) { | |||
69 |
1/1✓ Branch 1 taken 5 times.
|
1/1✓ Call 0 invoked.
|
10 | std::ostringstream vOut; | |
70 |
1/1✓ Branch 1 taken 5 times.
|
1/1✓ Call 0 invoked.
|
10 | vOut << vValue; | |
71 |
1/1✓ Branch 1 taken 5 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
10 | m_value = vOut.str(); | |
72 | 10 | return *this; | |||
73 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
10 | } | ||
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 | 17 | static std::string escapeXml(const std::string &vDatas) { | |||
95 |
1/1✓ Call 0 invoked.
|
17 | std::string escaped = vDatas; | ||
96 |
3/3✓ Branch 1 taken 17 times.
✓ Branch 4 taken 17 times.
✓ Branch 7 taken 17 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.
|
68 | replaceAll(escaped, "&", "&"); | |
97 |
3/3✓ Branch 1 taken 17 times.
✓ Branch 4 taken 17 times.
✓ Branch 7 taken 17 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.
|
68 | replaceAll(escaped, "<", "<"); | |
98 |
3/3✓ Branch 1 taken 17 times.
✓ Branch 4 taken 17 times.
✓ Branch 7 taken 17 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.
|
68 | replaceAll(escaped, "\"", """); | |
99 |
3/3✓ Branch 1 taken 17 times.
✓ Branch 4 taken 17 times.
✓ Branch 7 taken 17 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.
|
68 | replaceAll(escaped, "'", "'"); | |
100 |
3/3✓ Branch 1 taken 17 times.
✓ Branch 4 taken 17 times.
✓ Branch 7 taken 17 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.
|
51 | replaceAll(escaped, ">", ">"); | |
101 | 17 | 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, "<", "<"); | ||||
108 | replaceAll(unescaped, "&", "&"); | ||||
109 | replaceAll(unescaped, """, "\""); | ||||
110 | replaceAll(unescaped, "'", "'"); | ||||
111 | replaceAll(unescaped, ">", ">"); | ||||
112 | return unescaped; | ||||
113 | } | ||||
114 | |||||
115 | 85 | static void replaceAll(std::string &vStr, const std::string &vFrom, const std::string &vTo) { | |||
116 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 85 times.
|
1/1✓ Call 0 invoked.
|
85 | if (vFrom.empty()) return; |
117 | 85 | size_t startPos = 0; | |||
118 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 85 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 85 times.
|
1/1✓ Call 0 invoked.
|
89 | 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 | 15 | Node &addChild(const Node &vChild) { | |||
134 |
1/1✓ Call 0 invoked.
|
15 | m_children.push_back(vChild); | ||
135 |
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
15 | m_children.back().m_setParentNodeName(getName()); | ||
136 |
1/1✓ Call 0 invoked.
|
15 | return m_children.back(); | ||
137 | } | ||||
138 | |||||
139 | 1 | Node &addChild(const std::string &vName) { | |||
140 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | Node node(vName); | |
141 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
2 | return addChild(node); | |
142 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
1 | } | ||
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 | 1 | Node& addAttribute(const std::string& vKey, const T& vValue) { | |||
175 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | std::stringstream ss; | |
176 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | ss << vValue; | |
177 |
3/3✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
|
6/8✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✓ Call 11 invoked.
✗ Call 12 not invoked.
✗ Call 13 not invoked.
|
1 | m_attributes[vKey] = Attribute(ss.str()); | |
178 | 1 | return *this; | |||
179 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
1 | } | ||
180 | |||||
181 | 2 | Attribute& addAttribute(const std::string& vKey) { | |||
182 |
1/1✓ Branch 2 taken 2 times.
|
4/5✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
✗ Call 6 not invoked.
|
2 | m_attributes[vKey] = Attribute(); | |
183 |
1/1✓ Call 0 invoked.
|
2 | 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 | 12 | T getAttribute(const std::string &vKey) const { | |||
192 |
1/1✓ Call 0 invoked.
|
12 | T ret; | ||
193 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | std::stringstream ss; | |
194 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | 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.
|
12 | if (it != m_attributes.end()) { |
196 |
1/1✓ Branch 2 taken 12 times.
|
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
12 | ss << it->second; | |
197 | } | ||||
198 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | ss >> ret; | |
199 | 24 | return ret; | |||
200 |
1/3✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
|
12 | } | ||
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 | 5 | Node &setContent(const std::string &vContent) { | |||
211 |
1/1✓ Call 0 invoked.
|
5 | m_content = vContent; | ||
212 | 5 | return *this; | |||
213 | } | ||||
214 | |||||
215 | 20 | const std::string &getContent() const { | |||
216 | 20 | return m_content; | |||
217 | } | ||||
218 | |||||
219 | 9 | Nodes &getChildren() { return m_children; } | |||
220 | |||||
221 | 20 | const Nodes &getChildren() const { return m_children; } | |||
222 | |||||
223 | 1 | const std::string &getParentNodeName() const { | |||
224 | 1 | return m_parentNodeName; | |||
225 | } | ||||
226 | |||||
227 | 42 | const std::string &getName() const { | |||
228 | 42 | return m_name; | |||
229 | } | ||||
230 | |||||
231 | 17 | std::string dump(const xml::Node &vNode, const uint32_t vLevel = 0) const { | |||
232 |
1/1✓ Branch 1 taken 17 times.
|
1/1✓ Call 0 invoked.
|
17 | std::string indent(vLevel * 2, ' '); // Indentation based on the depth level | |
233 |
1/1✓ Branch 1 taken 17 times.
|
1/1✓ Call 0 invoked.
|
17 | std::ostringstream oss; | |
234 | |||||
235 |
1/1✓ Branch 1 taken 17 times.
|
1/1✓ Call 0 invoked.
|
17 | oss << indent; | |
236 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 2 times.
|
1/1✓ Call 0 invoked.
|
17 | if (vNode.m_getType() != xml::Node::Type::Comment) { |
237 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 5 taken 15 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
15 | oss << "<" << vNode.getName(); | |
238 |
2/2✓ Branch 4 taken 12 times.
✓ Branch 5 taken 15 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 15 times.
|
4/4✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
|
27 | for (const auto &attr: vNode.m_attributes) { |
239 |
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()) << "\""; | |
240 | } | ||||
241 | } else { | ||||
242 |
1/1✓ Branch 1 taken 2 times.
|
1/1✓ Call 0 invoked.
|
2 | oss << "<!-- "; | |
243 | } | ||||
244 | |||||
245 |
1/1✓ Call 0 invoked.
|
17 | const auto &content = vNode.getContent(); | ||
246 |
1/1✓ Call 0 invoked.
|
17 | const auto &children = vNode.getChildren(); | ||
247 | |||||
248 |
6/6✓ Branch 1 taken 12 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 10 times.
|
2/2✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 10 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
17 | if (content.empty() && children.empty()) { |
249 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 4 taken 7 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
7 | oss << "/>" << std::endl; | |
250 | } else { | ||||
251 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 2 times.
|
1/1✓ Call 0 invoked.
|
10 | if (vNode.m_getType() != xml::Node::Type::Comment) { |
252 |
1/1✓ Branch 1 taken 8 times.
|
1/1✓ Call 0 invoked.
|
8 | oss << ">"; | |
253 | } | ||||
254 |
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 (!content.empty()) { |
255 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 4 taken 5 times.
|
3/4✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
|
5 | oss << xml::Node::escapeXml(content); | |
256 | } | ||||
257 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 8 times.
|
1/1✓ Call 0 invoked.
|
10 | if (vNode.m_getType() == xml::Node::Type::Comment) { |
258 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
2 | oss << " -->" << std::endl; | |
259 | } | ||||
260 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 3 times.
|
2/2✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 3 times.
|
1/1✓ Call 0 invoked.
|
10 | if (!children.empty()) { |
261 |
1/1✓ Branch 1 taken 7 times.
|
1/1✓ Call 0 invoked.
|
7 | oss << std::endl; | |
262 |
2/2✓ Branch 4 taken 14 times.
✓ Branch 5 taken 7 times.
|
2/2✓ Decision 'true' taken 14 times.
✓ Decision 'false' taken 7 times.
|
4/4✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
|
21 | for (const auto &child: children) { |
263 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 4 taken 14 times.
|
4/5✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✗ Call 8 not invoked.
|
14 | oss << dump(child, vLevel + 1); | |
264 | } | ||||
265 |
1/1✓ Branch 1 taken 7 times.
|
1/1✓ Call 0 invoked.
|
7 | oss << indent; | |
266 | } | ||||
267 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 2 times.
|
1/1✓ Call 0 invoked.
|
10 | if (vNode.m_getType() != xml::Node::Type::Comment) { |
268 |
4/4✓ Branch 1 taken 8 times.
✓ Branch 5 taken 8 times.
✓ Branch 8 taken 8 times.
✓ Branch 11 taken 8 times.
|
5/5✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 7 invoked.
✓ Call 10 invoked.
|
8 | oss << "</" << vNode.getName() << ">" << std::endl; | |
269 | } | ||||
270 | } | ||||
271 | |||||
272 |
1/1✓ Branch 1 taken 17 times.
|
1/1✓ Call 0 invoked.
|
34 | return oss.str(); | |
273 |
2/4✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
17 | } | ||
274 | |||||
275 | 3 | std::string dump() const { | |||
276 |
1/1✓ Call 0 invoked.
|
3 | return dump(*this); | ||
277 | } | ||||
278 | |||||
279 | private: | ||||
280 | |||||
281 | 12 | void m_setAttribute(const std::string &vKey, const std::string &vValue) { | |||
282 |
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); | |
283 | 12 | } | |||
284 | |||||
285 | 17 | void m_setType(Type vType) { | |||
286 | 17 | m_type = vType; | |||
287 | 17 | } | |||
288 | |||||
289 | 47 | Type m_getType() const { | |||
290 | 47 | return m_type; | |||
291 | } | ||||
292 | |||||
293 | 15 | void m_setParentNodeName(const std::string &vName) { | |||
294 |
1/1✓ Call 0 invoked.
|
15 | m_parentNodeName = vName; | ||
295 | 15 | } | |||
296 | }; | ||||
297 | |||||
298 | template<> | ||||
299 | inline Node &Node::setContent(const bool &vContent) { | ||||
300 | m_content = vContent ? "true" : "false"; | ||||
301 | return *this; | ||||
302 | } | ||||
303 | |||||
304 | } // namespace xml | ||||
305 | |||||
306 | class Xml { | ||||
307 | private: | ||||
308 | xml::Node m_Root; | ||||
309 | // just during parsing, | ||||
310 | // for know what is the current node | ||||
311 | std::stack<xml::Node *> m_NodeStack; | ||||
312 | enum class TokenType { // | ||||
313 | OPENED = 0, | ||||
314 | CLOSED, | ||||
315 | OPENED_CLOSED, | ||||
316 | COMMENT, | ||||
317 | CONTENT, | ||||
318 | Count | ||||
319 | }; | ||||
320 | |||||
321 | public: | ||||
322 |
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) { | |
323 |
1/1✓ Branch 1 taken 3 times.
|
1/1✓ Call 0 invoked.
|
3 | m_NodeStack.push(&m_Root); | |
324 |
0/2✗ Call 0 not invoked.
✗ Call 1 not invoked.
|
3 | } | ||
325 | |||||
326 | 2 | xml::Node &getRoot() { | |||
327 | 2 | return m_Root; | |||
328 | } | ||||
329 | |||||
330 | bool parseFile(const std::string &vFilePathName) { | ||||
331 | std::ifstream docFile(vFilePathName, std::ios::in); | ||||
332 | if (docFile.is_open()) { | ||||
333 | std::stringstream strStream; | ||||
334 | strStream << docFile.rdbuf(); // read the file | ||||
335 | auto xml_content = strStream.str(); | ||||
336 | m_replaceString(xml_content, "\r\n", "\n"); | ||||
337 | m_replaceString(xml_content, "\r", "\n"); | ||||
338 | docFile.close(); | ||||
339 | return parseString(xml_content); | ||||
340 | } | ||||
341 | return false; | ||||
342 | } | ||||
343 | |||||
344 | 3 | bool parseString(const std::string &vDoc) { | |||
345 |
1/1✓ Branch 1 taken 3 times.
|
1/1✓ Call 0 invoked.
|
3 | auto tokens = m_tokenize(vDoc); | |
346 |
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()) { |
347 | ✗ | return false; | |||
348 | } | ||||
349 |
2/2✓ Branch 5 taken 40 times.
✓ Branch 6 taken 2 times.
|
2/2✓ Decision 'true' taken 40 times.
✓ Decision 'false' taken 2 times.
|
5/5✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
42 | for (const auto &token: tokens) { |
350 |
1/1✓ Call 0 invoked.
|
40 | std::string tagName; | ||
351 |
1/1✓ Call 0 invoked.
|
40 | std::map<std::string, std::string> attributes; | ||
352 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 40 times.
|
1/1✓ Call 0 invoked.
|
40 | if (token.first.empty()) { |
353 | ✗ | continue; | |||
354 | } | ||||
355 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 36 times.
|
40 | if (token.second == TokenType::CLOSED) { | |
356 |
1/1✓ Call 0 invoked.
|
4 | m_NodeStack.pop(); | ||
357 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 7 times.
|
2/2✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 21 times.
|
36 | } else if (token.second == TokenType::OPENED || // | |
358 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 6 times.
|
29 | token.second == TokenType::OPENED_CLOSED || // | ||
359 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
|
23 | token.second == TokenType::COMMENT) { | ||
360 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
|
2/2✓ Decision 'true' taken 13 times.
✓ Decision 'false' taken 2 times.
|
15 | if (token.second != TokenType::COMMENT) { | |
361 |
1/1✓ Branch 1 taken 13 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
13 | tagName = m_extractTagName(token.first); | |
362 | } | ||||
363 |
1/1✓ Branch 1 taken 15 times.
|
1/1✓ Call 0 invoked.
|
15 | xml::Node newNode(tagName); | |
364 |
1/1✓ Call 0 invoked.
|
15 | newNode.m_setType(xml::Node::Type::Token); | ||
365 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 13 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 13 times.
|
15 | if (token.second == TokenType::COMMENT) { | |
366 |
1/1✓ Call 0 invoked.
|
2 | newNode.m_setType(xml::Node::Type::Comment); | ||
367 |
1/1✓ Branch 1 taken 2 times.
|
1/1✓ Call 0 invoked.
|
2 | newNode.setContent(token.first); | |
368 | } else { | ||||
369 |
3/3✓ Branch 1 taken 13 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 12 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 12 times.
|
1/1✓ Call 0 invoked.
|
13 | if (!m_extractAttributes(tagName, token.first, attributes)) { |
370 | 1 | return false; | |||
371 | } | ||||
372 |
2/2✓ Branch 5 taken 12 times.
✓ Branch 6 taken 12 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 12 times.
|
5/5✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
24 | for (const auto &kv: attributes) { |
373 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | newNode.m_setAttribute(kv.first, kv.second); | |
374 | } | ||||
375 | } | ||||
376 |
1/1✓ Branch 2 taken 14 times.
|
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
14 | m_NodeStack.top()->addChild(newNode); | |
377 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
|
2/2✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 7 times.
|
14 | if (token.second == TokenType::OPENED) { | |
378 |
1/1✓ Branch 4 taken 7 times.
|
4/4✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
|
7 | m_NodeStack.push(const_cast<xml::Node *>(&m_NodeStack.top()->getChildren().back())); | |
379 | } | ||||
380 |
3/4✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
|
2/2✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 29 times.
|
1/2✓ Call 0 invoked.
✗ Call 5 not invoked.
|
50 | } else if (token.second == TokenType::CONTENT) { |
381 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 21 times.
✗ Decision 'false' not taken.
|
1/1✓ Call 0 invoked.
|
21 | if (!m_NodeStack.empty()) { |
382 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 18 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 18 times.
|
1/1✓ Call 0 invoked.
|
21 | if (token.first[0] != '\n') { |
383 |
1/1✓ Branch 2 taken 3 times.
|
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
3 | m_NodeStack.top()->setContent(token.first); | |
384 | } | ||||
385 | } | ||||
386 | } | ||||
387 |
2/4✓ Call 0 invoked.
✓ Call 4 invoked.
✗ Call 8 not invoked.
✗ Call 9 not invoked.
|
41 | } | ||
388 | 2 | return true; | |||
389 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
3 | } | ||
390 | |||||
391 | 3 | std::string dump() const { | |||
392 |
1/1✓ Call 0 invoked.
|
3 | return m_Root.dump(); | ||
393 | } | ||||
394 | |||||
395 | private: | ||||
396 | bool m_replaceString(std::string &str, const std::string &oldStr, const std::string &newStr) { | ||||
397 | bool found = false; | ||||
398 | size_t pos = 0; | ||||
399 | while ((pos = str.find(oldStr, pos)) != std::string::npos) { | ||||
400 | found = true; | ||||
401 | str.replace(pos, oldStr.length(), newStr); | ||||
402 | pos += newStr.length(); | ||||
403 | } | ||||
404 | return found; | ||||
405 | } | ||||
406 | |||||
407 | 3 | std::vector<std::pair<std::string, TokenType>> m_tokenize(const std::string &vDoc) { | |||
408 |
1/1✓ Call 0 invoked.
|
3 | std::vector<std::pair<std::string, TokenType>> tokens; | ||
409 | 3 | size_t pos = 0; | |||
410 |
1/1✓ Call 0 invoked.
|
3 | size_t length = vDoc.length(); | ||
411 | 3 | TokenType type = TokenType::Count; | |||
412 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 3 times.
|
2/2✓ Decision 'true' taken 43 times.
✓ Decision 'false' taken 3 times.
|
46 | while (pos < length) { | |
413 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 23 times.
|
2/2✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 23 times.
|
1/1✓ Call 0 invoked.
|
43 | if (vDoc[pos] == '<') { |
414 | 20 | type = TokenType::OPENED; | |||
415 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 15 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 15 times.
|
1/1✓ Call 0 invoked.
|
20 | if (vDoc[pos + 1] == '/') { |
416 | 5 | type = TokenType::CLOSED; | |||
417 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 13 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 13 times.
|
1/1✓ Call 0 invoked.
|
15 | } else if (vDoc[pos + 1] == '!') { |
418 | 2 | type = TokenType::COMMENT; | |||
419 | } | ||||
420 |
1/1✓ Call 0 invoked.
|
20 | size_t end = vDoc.find(">", pos); | ||
421 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 20 times.
|
20 | if (end == std::string::npos) { | |
422 | ✗ | break; | |||
423 | } | ||||
424 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 14 times.
|
2/2✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 14 times.
|
1/1✓ Call 0 invoked.
|
20 | if (vDoc[end - 1] == '/') { |
425 | 6 | type = TokenType::OPENED_CLOSED; | |||
426 | } | ||||
427 |
1/1✓ Branch 1 taken 20 times.
|
1/1✓ Call 0 invoked.
|
20 | const auto ss = vDoc.substr(pos, end + 1 - pos); | |
428 |
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.
|
20 | tokens.push_back(std::make_pair(ss, type)); | |
429 | 20 | pos = end + 1; | |||
430 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
20 | } else { | ||
431 |
1/1✓ Call 0 invoked.
|
23 | size_t end = vDoc.find('<', pos); | ||
432 |
1/1✓ Branch 1 taken 23 times.
|
1/1✓ Call 0 invoked.
|
23 | const auto ss = vDoc.substr(pos, end - pos); | |
433 |
2/2✓ Branch 1 taken 23 times.
✓ Branch 4 taken 23 times.
|
3/4✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
|
23 | tokens.push_back(std::make_pair(ss, TokenType::CONTENT)); | |
434 | 23 | pos = end; | |||
435 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
23 | } | ||
436 | } | ||||
437 | 6 | return tokens; | |||
438 | } | ||||
439 | |||||
440 | 13 | std::string m_extractTagName(const std::string &vLine) { | |||
441 |
1/1✓ Call 0 invoked.
|
13 | std::string ret; | ||
442 |
1/1✓ Call 0 invoked.
|
13 | size_t startPos = vLine.find('<') + 1; | ||
443 |
6/7✓ Branch 1 taken 14 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 13 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 13 times.
|
0/1? Decision couldn't be analyzed.
|
2/2✓ Call 0 invoked.
✓ Call 5 invoked.
|
14 | while (vLine.at(startPos) == ' ' && vLine.size() > startPos) { |
444 | 1 | ++startPos; | |||
445 | } | ||||
446 |
1/1✓ Call 0 invoked.
|
13 | size_t endPos = vLine.find_first_of(" \t>", startPos); | ||
447 |
1/1✓ Branch 1 taken 13 times.
|
1/1✓ Call 0 invoked.
|
26 | return vLine.substr(startPos, endPos - startPos); | |
448 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
13 | } | ||
449 | |||||
450 | // will remove space outside of <> and "" | ||||
451 | std::string m_trim1(const std::string &vToken) { | ||||
452 | std::string res; | ||||
453 | int32_t scope = 0; | ||||
454 | for (const auto c: vToken) { | ||||
455 | if (scope == 1) { | ||||
456 | res += c; | ||||
457 | } else if (c == '"') { | ||||
458 | if (scope == 0) { | ||||
459 | ++scope; | ||||
460 | } else { | ||||
461 | --scope; | ||||
462 | } | ||||
463 | } | ||||
464 | } | ||||
465 | return res; | ||||
466 | } | ||||
467 | |||||
468 | // will remove spaces from start and from end | ||||
469 | // if the token is like tk0 tk1 tk2, only tk0 will be returned | ||||
470 | 14 | std::string m_trim2(const std::string &vToken) { | |||
471 |
1/1✓ Call 0 invoked.
|
14 | std::string res; | ||
472 |
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) { |
473 |
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 != ' ') { | |
474 |
1/1✓ Branch 1 taken 70 times.
|
1/1✓ Call 0 invoked.
|
70 | res += c; | |
475 |
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()) { |
476 | 2 | break; | |||
477 | } | ||||
478 | } | ||||
479 | 14 | return res; | |||
480 | } | ||||
481 | |||||
482 | 13 | bool m_extractAttributes(const std::string &vTagName, const std::string &vLine, | |||
483 | std::map<std::string, std::string> &attributes) { | ||||
484 |
1/1✓ Call 0 invoked.
|
13 | size_t startPos = vLine.find(vTagName); | ||
485 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 13 times.
✗ Decision 'false' not taken.
|
13 | if (startPos != std::string::npos) { | |
486 |
1/1✓ Call 0 invoked.
|
13 | startPos += vTagName.size(); | ||
487 |
1/1✓ Call 0 invoked.
|
13 | startPos = vLine.find(' ', startPos); | ||
488 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 11 times.
|
2/2✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 11 times.
|
26 | while (startPos != std::string::npos) { | |
489 |
1/1✓ Call 0 invoked.
|
15 | startPos = vLine.find_first_not_of(" \t", startPos); | ||
490 |
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) == '>') { |
491 | 1 | break; | |||
492 | } | ||||
493 |
1/1✓ Call 0 invoked.
|
14 | size_t equalsPos = vLine.find('=', startPos); | ||
494 |
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) { | |
495 | 1 | return false; | |||
496 | } | ||||
497 |
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)); | |
498 | 14 | startPos = equalsPos + 1; | |||
499 |
1/1✓ Call 0 invoked.
|
14 | char quoteChar = vLine[startPos]; | ||
500 |
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 == ' ') { | |
501 |
1/1✓ Call 0 invoked.
|
2 | quoteChar = vLine[++startPos]; | ||
502 | } | ||||
503 |
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 == '\'') { | |
504 | 13 | startPos++; | |||
505 |
1/1✓ Call 0 invoked.
|
13 | size_t endPos = vLine.find(quoteChar, startPos); | ||
506 |
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) { | |
507 |
1/1✓ Branch 1 taken 13 times.
|
1/1✓ Call 0 invoked.
|
13 | std::string value = vLine.substr(startPos, endPos - startPos); | |
508 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 4 taken 13 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
13 | attributes[key] = value; | |
509 |
1/1✓ Call 0 invoked.
|
13 | startPos = vLine.find(' ', endPos); // Passer ? l'attribut suivant | ||
510 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
13 | } else { | ||
511 | #ifdef LogVarError | ||||
512 | LogVarError("The attribut '%s' have invalid value", key.c_str()); | ||||
513 | #endif | ||||
514 | ✗ | return false; // Erreur : guillemets/apostrophes non ferm?s | |||
515 | } | ||||
516 | 13 | } else { | |||
517 | #ifdef LogVarError | ||||
518 | LogVarError("The attribut '%s' have invalid value", key.c_str()); | ||||
519 | #endif | ||||
520 | 1 | return false; // Erreur : attribut sans guillemets ou apostrophes | |||
521 | } | ||||
522 |
1/2✓ Call 0 invoked.
✗ Call 3 not invoked.
|
14 | } | ||
523 | 12 | return true; | |||
524 | } | ||||
525 | ✗ | return false; | |||
526 | } | ||||
527 | }; | ||||
528 | |||||
529 | } // namespace ez | ||||
530 |
Directory: | include/ezlibs/ |
---|---|
File: | ezLzw.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 57 | 59 | 96.6% |
Functions: | 10 | 10 | 100.0% |
Branches: | 48 | 52 | 92.3% |
Decisions: | 11 | 12 | 91.7% |
Calls: | 79 | 95 | 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 | // ezLzw is part of the ezLibs project : https://github.com/aiekick/ezLibs.git | ||||
28 | |||||
29 | #include <string> | ||||
30 | #include <vector> | ||||
31 | #include <cstdint> | ||||
32 | #include <fstream> | ||||
33 | #include <iostream> | ||||
34 | #include <unordered_map> | ||||
35 | |||||
36 | namespace ez { | ||||
37 | namespace comp { | ||||
38 | |||||
39 | // LZW algo : | ||||
40 | // https://fr.wikipedia.org/wiki/Lempel-Ziv-Welch | ||||
41 | |||||
42 | class Lzw { | ||||
43 | friend class TestLzw; | ||||
44 | |||||
45 | private: | ||||
46 | typedef uint16_t DataType; | ||||
47 | std::vector<DataType> m_datas; | ||||
48 | std::unordered_map<std::string, uint16_t> m_dicoComp; | ||||
49 | std::unordered_map<uint16_t, std::string> m_dicoDeComp; | ||||
50 | |||||
51 | public: | ||||
52 |
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
1 | Lzw() { | ||
53 |
1/1✓ Call 0 invoked.
|
1 | std::string c; | ||
54 |
2/2✓ Branch 0 taken 256 times.
✓ Branch 1 taken 1 times.
|
2/2✓ Decision 'true' taken 256 times.
✓ Decision 'false' taken 1 times.
|
257 | for (uint16_t i = 0; i < 256; ++i) { | |
55 |
1/1✓ Branch 1 taken 256 times.
|
1/1✓ Call 0 invoked.
|
256 | c = static_cast<char>(i); | |
56 |
1/1✓ Branch 1 taken 256 times.
|
1/1✓ Call 0 invoked.
|
256 | m_dicoComp[c] = i; | |
57 |
2/2✓ Branch 1 taken 256 times.
✓ Branch 4 taken 256 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
256 | m_dicoDeComp[i] = c; | |
58 | } | ||||
59 |
1/5✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
|
1 | } | ||
60 |
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
1 | ~Lzw() = default; | ||
61 | |||||
62 | Lzw& compressFile(const std::string& vFilePathName) { | ||||
63 | std::ifstream inputFile(vFilePathName, std::ios::binary); | ||||
64 | if (inputFile.is_open()) { | ||||
65 | std::vector<DataType> buffer((std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>()); | ||||
66 | inputFile.close(); | ||||
67 | m_datas = m_compress(buffer); | ||||
68 | } | ||||
69 | return *this; | ||||
70 | } | ||||
71 | |||||
72 | Lzw& compresss(void* vBuffer, size_t vBufferLen) { | ||||
73 | std::vector<DataType> buffer(static_cast<DataType*>(vBuffer), static_cast<DataType*>(vBuffer) + vBufferLen); | ||||
74 | m_datas = m_compress(buffer); | ||||
75 | return *this; | ||||
76 | } | ||||
77 | |||||
78 | 1 | Lzw& compresss(const std::string& vBuffer) { | |||
79 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
|
5/6✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 7 invoked.
✓ Call 8 invoked.
✗ Call 9 not invoked.
|
1 | m_datas = m_compress(m_stringToVector(vBuffer)); | |
80 | 1 | return *this; | |||
81 | } | ||||
82 | |||||
83 | Lzw& extractFile(const std::string& vFilePathName) { | ||||
84 | std::ifstream inputFile(vFilePathName, std::ios::binary); | ||||
85 | if (inputFile.is_open()) { | ||||
86 | std::vector<DataType> buffer((std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>()); | ||||
87 | inputFile.close(); | ||||
88 | m_datas = m_extract(buffer); | ||||
89 | } | ||||
90 | return *this; | ||||
91 | } | ||||
92 | |||||
93 | 1 | Lzw& extract(const std::vector<DataType>& vDatas) { | |||
94 |
1/1✓ Branch 1 taken 1 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
1 | m_datas = m_extract(vDatas); | |
95 | 1 | return *this; | |||
96 | } | ||||
97 | |||||
98 | Lzw& extract(void* vBuffer, size_t vBufferLen) { | ||||
99 | std::vector<DataType> buffer(static_cast<DataType*>(vBuffer), static_cast<DataType*>(vBuffer) + vBufferLen); | ||||
100 | m_datas = m_extract(buffer); | ||||
101 | return *this; | ||||
102 | } | ||||
103 | |||||
104 | Lzw& extract(const std::string& vBuffer) { | ||||
105 | std::vector<DataType> buffer(vBuffer.begin(), vBuffer.end()); | ||||
106 | m_datas = m_extract(buffer); | ||||
107 | return *this; | ||||
108 | } | ||||
109 | |||||
110 | 1 | std::vector<DataType> getDatas() { | |||
111 |
1/1✓ Call 0 invoked.
|
1 | return m_datas; | ||
112 | } | ||||
113 | |||||
114 | 1 | std::string getDatasToString() { | |||
115 |
1/1✓ Call 0 invoked.
|
1 | return m_vectorToString(m_datas); | ||
116 | } | ||||
117 | |||||
118 | Lzw& save(const std::string& vFilePathName, bool vNoExcept = false) { | ||||
119 | std::ofstream file(vFilePathName, std::ios::binary); | ||||
120 | if (!file && !vNoExcept) { | ||||
121 | throw std::runtime_error("Impossible d'ouvrir le fichier."); | ||||
122 | } | ||||
123 | auto dataSize = static_cast<uint32_t>(m_datas.size()); | ||||
124 | file.write(reinterpret_cast<const char*>(&dataSize), sizeof(dataSize)); | ||||
125 | file.write(reinterpret_cast<const char*>(m_datas.data()), m_datas.size()); | ||||
126 | file.close(); | ||||
127 | return *this; | ||||
128 | } | ||||
129 | |||||
130 | private: | ||||
131 | 1 | static std::vector<DataType> m_stringToVector(const std::string& str) { | |||
132 |
1/1✓ Branch 3 taken 1 times.
|
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
3 | return {str.begin(), str.end()}; | |
133 | } | ||||
134 | |||||
135 | 1 | static std::string m_vectorToString(const std::vector<DataType>& vec) { | |||
136 |
1/1✓ Branch 3 taken 1 times.
|
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
3 | return {vec.begin(), vec.end()}; | |
137 | } | ||||
138 | |||||
139 | /* | ||||
140 | * PSEUDOCODE | ||||
141 | 1 Initialize table with single character strings | ||||
142 | 2 P = first input character | ||||
143 | 3 WHILE not end of input stream | ||||
144 | 4 C = next input character | ||||
145 | 5 IF P + C is in the string table | ||||
146 | 6 P = P + C | ||||
147 | 7 ELSE | ||||
148 | 8 output the code for P | ||||
149 | 9 add P + C to the string table | ||||
150 | 10 P = C | ||||
151 | 11 END WHILE | ||||
152 | 12 output code for P | ||||
153 | */ | ||||
154 | |||||
155 | 1 | std::vector<DataType> m_compress(const std::vector<DataType>& vDatas) { | |||
156 |
1/1✓ Call 0 invoked.
|
1 | std::vector<DataType> result; | ||
157 | 1 | uint16_t code = 256U; | |||
158 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | std::string p, c; | ||
159 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
1 | p += static_cast<char>(vDatas.at(0)); | |
160 |
2/2✓ Branch 1 taken 23 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 23 times.
✓ Decision 'false' taken 1 times.
|
1/1✓ Call 0 invoked.
|
24 | for (uint16_t idx = 1U; idx < vDatas.size(); ++idx) { |
161 |
2/2✓ Branch 1 taken 23 times.
✓ Branch 4 taken 23 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
23 | c = static_cast<char>(vDatas.at(idx)); | |
162 |
1/1✓ Branch 1 taken 23 times.
|
1/1✓ Call 0 invoked.
|
23 | auto pc = p + c; | |
163 |
3/3✓ Branch 2 taken 23 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 15 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 15 times.
|
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
|
23 | if (m_dicoComp.find(pc) != m_dicoComp.end()) { |
164 |
1/1✓ Branch 1 taken 8 times.
|
1/1✓ Call 0 invoked.
|
8 | p = pc; | |
165 | } else { | ||||
166 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
15 | result.push_back(m_dicoComp.at(p)); | |
167 |
1/1✓ Branch 1 taken 15 times.
|
1/1✓ Call 0 invoked.
|
15 | m_dicoComp[pc] = code++; | |
168 |
1/1✓ Branch 1 taken 15 times.
|
1/1✓ Call 0 invoked.
|
15 | p = c; | |
169 | } | ||||
170 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
23 | } | ||
171 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
1 | result.push_back(m_dicoComp.at(p)); | |
172 | 2 | return result; | |||
173 |
2/5✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
|
1 | } | ||
174 | |||||
175 | /* | ||||
176 | * PSEUDOCODE | ||||
177 | 1 Initialize table with single character strings | ||||
178 | 2 OLD = first input code | ||||
179 | 3 output translation of OLD | ||||
180 | 4 WHILE not end of input stream | ||||
181 | 5 NEW = next input code | ||||
182 | 6 IF NEW is not in the string table | ||||
183 | 7 S = translation of OLD | ||||
184 | 8 S = S + C | ||||
185 | 9 ELSE | ||||
186 | 10 S = translation of NEW | ||||
187 | 11 output S | ||||
188 | 12 C = first character of S | ||||
189 | 13 OLD + C to the string table | ||||
190 | 14 OLD = NEW | ||||
191 | 15 END WHILE | ||||
192 | */ | ||||
193 | 1 | std::vector<DataType> m_extract(const std::vector<DataType>& vDatas) { | |||
194 |
1/1✓ Call 0 invoked.
|
1 | std::vector<DataType> result; | ||
195 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | DataType lop = vDatas.at(0), nop; | |
196 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
1 | std::string p = m_dicoDeComp.at(lop); | |
197 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | std::string c = p; | |
198 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
1 | result.push_back(p.at(0)); | |
199 | 1 | uint16_t code = 256U; | |||
200 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 1 times.
|
1/1✓ Call 0 invoked.
|
16 | for (size_t idx = 1U; idx < vDatas.size(); ++idx) { |
201 |
1/1✓ Call 0 invoked.
|
15 | nop = vDatas[idx]; | ||
202 |
2/3✓ Branch 2 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 15 times.
|
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
|
15 | if (m_dicoDeComp.find(nop) == m_dicoDeComp.end()) { |
203 |
0/2✗ Call 0 not invoked.
✗ Call 3 not invoked.
|
✗ | p = m_dicoDeComp.at(lop); | ||
204 |
0/1✗ Call 0 not invoked.
|
✗ | p += c; | ||
205 | } else { | ||||
206 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
15 | p = m_dicoDeComp.at(nop); | |
207 | } | ||||
208 |
2/2✓ Branch 5 taken 23 times.
✓ Branch 6 taken 15 times.
|
2/2✓ Decision 'true' taken 23 times.
✓ Decision 'false' taken 15 times.
|
5/5✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
38 | for (DataType ch : p) { |
209 |
1/1✓ Branch 1 taken 23 times.
|
1/1✓ Call 0 invoked.
|
23 | result.push_back(ch); | |
210 | } | ||||
211 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
15 | c = p[0]; | |
212 |
3/3✓ Branch 1 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
|
5/6✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✓ Call 9 invoked.
✓ Call 10 invoked.
✗ Call 11 not invoked.
|
15 | m_dicoDeComp[code++] = m_dicoDeComp.at(lop) + c; | |
213 | 15 | lop = nop; | |||
214 | } | ||||
215 | 2 | return result; | |||
216 |
2/5✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
|
1 | } | ||
217 | }; | ||||
218 | |||||
219 | } // namespace comp | ||||
220 | } // namespace ez | ||||
221 |
Directory: | include/ezlibs/ |
---|---|
File: | ezCnt.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezVoxWriter.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezMath.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezAABBCC.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezVec3.hpp |
Date: | 2025-01-29 20:42:40 |
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 | } // namespace ez | ||||
514 |
Directory: | include/ezlibs/ |
---|---|
File: | ezCron.hpp |
Date: | 2025-01-29 20:42:40 |
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 8 times.
✓ Branch 1 taken 2 times.
|
18 | return (vValue >= field.range.first && // | ||
547 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
|
18 | 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: | ezNamedPipe.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezBmp.hpp |
Date: | 2025-01-29 20:42:40 |
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 | #include <fstream> | ||||
30 | #include <vector> | ||||
31 | #include <cstdint> | ||||
32 | #include <stdexcept> | ||||
33 | #include <string> | ||||
34 | |||||
35 | namespace ez { | ||||
36 | namespace img { | ||||
37 | |||||
38 | /* | ||||
39 | Bitmap picture file saver | ||||
40 | |||||
41 | ez::img::Bmp() | ||||
42 | .setSize(10,10) // width, height 10 | ||||
43 | .setPixel(0,0,255,100,200) // byte form | ||||
44 | .setPixel(5,5,0.5,0.2,0.8) // linear float form | ||||
45 | .save("test.bmp"); // save to file test.bmp | ||||
46 | */ | ||||
47 | |||||
48 | class Bmp { | ||||
49 | friend class TestBmp; | ||||
50 | |||||
51 | private: | ||||
52 | uint32_t m_width{}; | ||||
53 | uint32_t m_height{}; | ||||
54 | std::vector<uint8_t> m_pixels; | ||||
55 | |||||
56 | public: | ||||
57 |
1/1✓ Call 0 invoked.
|
1 | Bmp() = default; | ||
58 |
1/1✓ Call 0 invoked.
|
1 | ~Bmp() = default; | ||
59 | |||||
60 | 1 | Bmp& setSize(uint32_t vWidth, uint32_t vHeight) { | |||
61 |
1/1✓ Call 0 invoked.
|
1 | m_width = std::move(vWidth); | ||
62 |
1/1✓ Call 0 invoked.
|
1 | m_height = std::move(vHeight); | ||
63 |
1/1✓ Call 0 invoked.
|
1 | m_pixels.resize(m_width * m_height * 3U); | ||
64 | 1 | return *this; | |||
65 | } | ||||
66 | |||||
67 | Bmp& clear() { | ||||
68 | m_width = 0U; | ||||
69 | m_height = 0U; | ||||
70 | m_pixels.clear(); | ||||
71 | return *this; | ||||
72 | } | ||||
73 | |||||
74 | 10000 | Bmp& setPixel(int32_t vX, int32_t vY, int32_t vRed, int32_t vGreen, int32_t vBlue) { | |||
75 | 10000 | auto x = static_cast<uint32_t>(vX); | |||
76 | 10000 | auto y = static_cast<uint32_t>(vY); | |||
77 |
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) { | |
78 | 10000 | size_t index = static_cast<size_t>((vY * m_width + vX) * 3); | |||
79 | // BMP save color in BGR | ||||
80 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
10000 | m_pixels[index++] = m_getByteFromInt32(vBlue); | ||
81 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
10000 | m_pixels[index++] = m_getByteFromInt32(vGreen); | ||
82 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
10000 | m_pixels[index] = m_getByteFromInt32(vRed); | ||
83 | } | ||||
84 | 10000 | return *this; | |||
85 | } | ||||
86 | |||||
87 | Bmp& setPixel(int32_t vX, int32_t vY, float vRed, float vGreen, float vBlue) { | ||||
88 | return setPixel(vX, // | ||||
89 | vY, | ||||
90 | m_getByteFromLinearFloat(vRed), | ||||
91 | m_getByteFromLinearFloat(vGreen), | ||||
92 | m_getByteFromLinearFloat(vBlue)); | ||||
93 | } | ||||
94 | |||||
95 | // Sauvegarde l'image en tant que fichier BMP | ||||
96 | 1 | Bmp& save(const std::string& filename) { | |||
97 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | std::ofstream file(filename, std::ios::binary); | |
98 |
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) { |
99 |
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."); | ||
100 | } | ||||
101 | |||||
102 | 1 | int paddingSize = (4 - (m_width * 3) % 4) % 4; | |||
103 | 1 | int fileSize = 54 + (m_width * m_height * 3) + (m_height * paddingSize); | |||
104 | |||||
105 | // En-t�te de fichier BMP | ||||
106 | 1 | uint8_t fileHeader[14] = { | |||
107 | 'B', | ||||
108 | 'M', // Signature | ||||
109 | 0, | ||||
110 | 0, | ||||
111 | 0, | ||||
112 | 0, // Taille du fichier | ||||
113 | 0, | ||||
114 | 0, | ||||
115 | 0, | ||||
116 | 0, // R�serv� | ||||
117 | 54, | ||||
118 | 0, | ||||
119 | 0, | ||||
120 | 0 // Offset vers les donn�es d'image | ||||
121 | }; | ||||
122 | |||||
123 | // Ins�rer la taille du fichier dans l'en-t�te | ||||
124 | 1 | fileHeader[2] = fileSize; | |||
125 | 1 | fileHeader[3] = fileSize >> 8; | |||
126 | 1 | fileHeader[4] = fileSize >> 16; | |||
127 | 1 | fileHeader[5] = fileSize >> 24; | |||
128 | |||||
129 | // En-t�te d'information BMP | ||||
130 | 1 | uint8_t infoHeader[40] = { | |||
131 | 40, 0, 0, 0, // Taille de l'en-t�te d'information | ||||
132 | 0, 0, 0, 0, // Largeur | ||||
133 | 0, 0, 0, 0, // Hauteur | ||||
134 | 1, 0, // Nombre de plans (1) | ||||
135 | 24, 0, // Bits par pixel (24 bits) | ||||
136 | 0, 0, 0, 0, // Compression (aucune) | ||||
137 | 0, 0, 0, 0, // Taille de l'image (non compress�e) | ||||
138 | 0, 0, 0, 0, // R�solution horizontale (pixels par m�tre) | ||||
139 | 0, 0, 0, 0, // R�solution verticale (pixels par m�tre) | ||||
140 | 0, 0, 0, 0, // Couleurs dans la palette | ||||
141 | 0, 0, 0, 0 // Couleurs importantes | ||||
142 | }; | ||||
143 | |||||
144 | // Ins�rer la largeur et la hauteur dans l'en-t�te d'information | ||||
145 | 1 | infoHeader[4] = m_width; | |||
146 | 1 | infoHeader[5] = m_width >> 8; | |||
147 | 1 | infoHeader[6] = m_width >> 16; | |||
148 | 1 | infoHeader[7] = m_width >> 24; | |||
149 | 1 | infoHeader[8] = m_height; | |||
150 | 1 | infoHeader[9] = m_height >> 8; | |||
151 | 1 | infoHeader[10] = m_height >> 16; | |||
152 | 1 | infoHeader[11] = m_height >> 24; | |||
153 | |||||
154 | // �crire les en-t�tes dans le fichier | ||||
155 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | file.write(reinterpret_cast<char*>(fileHeader), sizeof(fileHeader)); | |
156 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | file.write(reinterpret_cast<char*>(infoHeader), sizeof(infoHeader)); | |
157 | |||||
158 | // �crire les donn�es des pixels | ||||
159 |
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 | |
160 |
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) { | |
161 | 10000 | size_t index = static_cast<size_t>((y * m_width + x) * 3); | |||
162 |
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); | |
163 | } | ||||
164 | // Ajout de padding si n�cessaire | ||||
165 | 100 | uint8_t padding[3] = {0, 0, 0}; | |||
166 |
1/1✓ Branch 1 taken 100 times.
|
1/1✓ Call 0 invoked.
|
100 | file.write(reinterpret_cast<char*>(padding), paddingSize); | |
167 | } | ||||
168 | |||||
169 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | file.close(); | |
170 | 1 | return *this; | |||
171 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
1 | } | ||
172 | |||||
173 | private: | ||||
174 | 30000 | uint8_t m_getByteFromInt32(int32_t vValue) { | |||
175 |
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) { | |
176 | ✗ | vValue = 0; | |||
177 | } | ||||
178 |
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) { | |
179 | ✗ | vValue = 255; | |||
180 | } | ||||
181 | 30000 | return static_cast<uint8_t>(vValue); | |||
182 | } | ||||
183 | uint8_t m_getByteFromLinearFloat(float vValue) { | ||||
184 | if (vValue < 0.0f) { | ||||
185 | vValue = 0.0f; | ||||
186 | } | ||||
187 | if (vValue > 1.0f) { | ||||
188 | vValue = 1.0f; | ||||
189 | } | ||||
190 | return static_cast<uint8_t>(vValue * 255.0f); | ||||
191 | } | ||||
192 | }; | ||||
193 | |||||
194 | } // namespace img | ||||
195 | } // namespace ez | ||||
196 |
Directory: | include/ezlibs/ |
---|---|
File: | ezVdbWriter.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezCmdProcessor.hpp |
Date: | 2025-01-29 20:42:40 |
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 aprt 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 |
Directory: | include/ezlibs/ |
---|---|
File: | ezVec4.hpp |
Date: | 2025-01-29 20:42:40 |
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 | } // namespace ez | ||||
538 |
Directory: | include/ezlibs/ |
---|---|
File: | ezGraph.hpp |
Date: | 2025-01-29 20:42:40 |
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: | ezArgs.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 202 | 234 | 86.3% |
Functions: | 24 | 25 | 96.0% |
Branches: | 194 | 269 | 72.1% |
Decisions: | 95 | 126 | 75.4% |
Calls: | 250 | 387 | 64.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 | |||||
46 | class Args { | ||||
47 | private: | ||||
48 | class Argument { | ||||
49 | friend class Args; | ||||
50 | |||||
51 | private: | ||||
52 | std::vector<std::string> m_base_args; // base args | ||||
53 | std::set<std::string> m_full_args; // full args | ||||
54 | char one_char_arg = 0; | ||||
55 | std::string m_help_text; | ||||
56 | std::string m_help_var_name; | ||||
57 | std::string m_type; | ||||
58 | bool m_required = false; | ||||
59 | char m_delimiter = 0; // delimiter used for arguments : toto a, toto=a, toto:a, etc... | ||||
60 | bool m_is_present = false; // found during parsing | ||||
61 | bool m_has_value = false; // found during parsing | ||||
62 | std::string m_value; // value | ||||
63 | |||||
64 | public: | ||||
65 |
6/6✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
✓ Call 5 invoked.
|
26 | Argument() = default; | ||
66 | |||||
67 | 25 | Argument &help(const std::string &vHelp, const std::string &vVarName = {}) { | |||
68 |
1/1✓ Call 0 invoked.
|
25 | m_help_text = vHelp; | ||
69 |
1/1✓ Call 0 invoked.
|
25 | m_help_var_name = vVarName; | ||
70 | 25 | return *this; | |||
71 | } | ||||
72 | |||||
73 | Argument &def(const std::string &vDefValue) { | ||||
74 | m_value = vDefValue; | ||||
75 | return *this; | ||||
76 | } | ||||
77 | |||||
78 | Argument &type(const std::string &vType) { | ||||
79 | m_type = vType; | ||||
80 | return *this; | ||||
81 | } | ||||
82 | |||||
83 | 9 | Argument &delimiter(char vDelimiter) { | |||
84 | 9 | m_delimiter = vDelimiter; | |||
85 | 9 | return *this; | |||
86 | } | ||||
87 | |||||
88 | Argument &required(bool vValue) { | ||||
89 | m_required = vValue; | ||||
90 | return *this; | ||||
91 | } | ||||
92 | |||||
93 | private: | ||||
94 | typedef std::pair<std::string, std::string> HelpCnt; | ||||
95 | |||||
96 | 12 | HelpCnt m_getHelp(bool vPositional, size_t &vInOutFirstColSize) const { | |||
97 |
1/1✓ Call 0 invoked.
|
12 | HelpCnt res; | ||
98 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | std::stringstream ss; | |
99 |
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) { | |
100 |
0/1✗ Call 0 not invoked.
|
✗ | std::string token = m_help_var_name; | ||
101 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
0/1✗ Call 0 not invoked.
|
✗ | if (token.empty()) { | |
102 |
0/3✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
|
✗ | token = *(m_base_args.begin()); | ||
103 | } | ||||
104 |
0/2✗ Call 0 not invoked.
✗ Call 3 not invoked.
|
✗ | ss << " " << token; | ||
105 |
0/2✗ Call 0 not invoked.
✗ Call 1 not invoked.
|
✗ | } else { | ||
106 | 12 | size_t idx = 0; | |||
107 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | ss << " "; | |
108 |
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) { |
109 |
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) { | |
110 |
1/1✓ Branch 1 taken 6 times.
|
1/1✓ Call 0 invoked.
|
6 | ss << ", "; | |
111 | } | ||||
112 |
1/1✓ Branch 1 taken 18 times.
|
1/1✓ Call 0 invoked.
|
18 | ss << arg; | |
113 | } | ||||
114 |
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()) { |
115 |
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; | |
116 | } | ||||
117 | } | ||||
118 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | auto ret = ss.str(); | |
119 |
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()) { |
120 |
1/1✓ Call 0 invoked.
|
5 | vInOutFirstColSize = ret.size(); | ||
121 | } | ||||
122 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
24 | return std::make_pair(ret, m_help_text); | |
123 |
3/6✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
|
12 | } | ||
124 | }; | ||||
125 | |||||
126 | |||||
127 | private: | ||||
128 | std::string m_AppName; | ||||
129 | std::string m_HelpHeader; | ||||
130 | std::string m_HelpFooter; | ||||
131 | std::string m_HelpDescription; | ||||
132 | Argument m_HelpArgument; | ||||
133 | std::vector<Argument> m_Positionals; | ||||
134 | std::vector<Argument> m_Optionals; | ||||
135 | |||||
136 | public: | ||||
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 | 4 | void printHelp() const { | |||
231 |
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.
|
12 | std::cout << getHelp() << std::endl; | |
232 | 4 | } | |||
233 | |||||
234 | 6 | bool parse(int32_t vArgc, char **vArgv, int32_t vStartIdx = 1U) { | |||
235 | 6 | size_t positional_idx = 0; | |||
236 |
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) { | |
237 |
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]); | |
238 | |||||
239 | // print help | ||||
240 |
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()) { |
241 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | printHelp(); | |
242 | 1 | return true; | |||
243 | } | ||||
244 | |||||
245 | // get args values | ||||
246 |
1/1✓ Branch 1 taken 14 times.
|
1/1✓ Call 0 invoked.
|
14 | std::string token = arg; | |
247 |
1/1✓ Call 0 invoked.
|
14 | std::string value; | ||
248 | 14 | bool is_optional = false; | |||
249 | 14 | bool check_for_value = false; | |||
250 |
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) { |
251 | 37 | check_for_value = false; | |||
252 |
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) { | |
253 |
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 != ' ') { | |
254 |
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) { |
255 |
1/1✓ Branch 1 taken 3 times.
|
1/1✓ Call 0 invoked.
|
3 | auto arr = ez::str::splitStringToVector(token, arg_ref.m_delimiter); | |
256 |
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) { |
257 |
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); | |
258 |
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); | |
259 | } else { | ||||
260 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
0/1✗ Call 0 not invoked.
|
✗ | 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 + "\". no value"); | ||
262 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
0/1✗ Call 0 not invoked.
|
✗ | } else if (arr.size() > 2) { | |
263 | throw std::runtime_error( | ||||
264 |
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.
|
✗ | "bad parsing of key \"" + token + "\". more than one value"); | ||
265 | } | ||||
266 | } | ||||
267 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
3 | } | ||
268 | } | ||||
269 | } | ||||
270 |
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) { | |
271 |
1/1✓ Call 0 invoked.
|
16 | auto p = token.find(arg_ref.one_char_arg); | ||
272 |
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) { | |
273 | 9 | arg_ref.m_is_present = true; | |||
274 | 9 | is_optional = true; | |||
275 |
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)) { |
276 | 2 | check_for_value = true; | |||
277 | } | ||||
278 | } | ||||
279 |
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()) { |
280 | 8 | arg_ref.m_is_present = true; | |||
281 | 8 | is_optional = true; | |||
282 | 8 | check_for_value = true; | |||
283 | } | ||||
284 |
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) { | |
285 |
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 == ' ') { | |
286 |
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 < (vArgc + 1)) { | |
287 |
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); | |
288 |
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) { | |
289 |
1/1✓ Branch 1 taken 3 times.
|
1/1✓ Call 0 invoked.
|
3 | arg_ref.m_value = vArgv[++idx]; | |
290 | 3 | arg_ref.m_has_value = true; | |||
291 | } | ||||
292 | } | ||||
293 |
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) { | |
294 |
1/1✓ Branch 1 taken 5 times.
|
1/1✓ Call 0 invoked.
|
5 | auto *existingArg = m_getArgumentPtr(value, true); | |
295 |
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) { | |
296 |
1/1✓ Branch 1 taken 5 times.
|
1/1✓ Call 0 invoked.
|
5 | arg_ref.m_value = value; | |
297 | 5 | arg_ref.m_has_value = true; | |||
298 | } | ||||
299 | } | ||||
300 | } | ||||
301 | } | ||||
302 | |||||
303 | // positionals | ||||
304 |
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) { | |
305 |
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()) { |
306 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | auto &positional = m_Positionals.at(positional_idx); | |
307 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | positional.m_value = arg; | |
308 | 4 | positional.m_has_value = true; | |||
309 | 4 | ++positional_idx; | |||
310 | } | ||||
311 | } | ||||
312 |
3/6✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
|
15 | } | ||
313 | |||||
314 |
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 | |
315 |
0/1✗ Call 0 not invoked.
|
✗ | !m_Positionals.empty()) { // some positionnal are wanted | ||
316 |
0/1✗ Call 0 not invoked.
|
✗ | printHelp(); | ||
317 | } | ||||
318 | |||||
319 | 5 | return true; | |||
320 | } | ||||
321 | |||||
322 | private: | ||||
323 | 62 | const Argument *m_getArgumentPtr(const std::string &vKey, bool vNoExcept = false) const { | |||
324 | 62 | const Argument *ret = nullptr; | |||
325 |
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) { |
326 |
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()) { |
327 | 8 | ret = &arg; | |||
328 | } | ||||
329 | } | ||||
330 |
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) { | |
331 |
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) { |
332 |
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()) { |
333 | 42 | ret = &arg; | |||
334 | } | ||||
335 | } | ||||
336 | } | ||||
337 |
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) { | |
338 |
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"); | ||
339 | } | ||||
340 | 62 | return ret; | |||
341 | } | ||||
342 | |||||
343 | 22 | Argument &m_addOptional(Argument &vInOutArgument, const std::string &vKey) { | |||
344 |
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()) { |
345 |
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"); | ||
346 | } | ||||
347 |
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, '/'); | |
348 |
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) { |
349 |
1/1✓ Branch 1 taken 34 times.
|
1/1✓ Call 0 invoked.
|
34 | vInOutArgument.m_full_args.emplace(a); | |
350 | } | ||||
351 |
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) { |
352 | // tofix : may fail if arg is --toto-titi. | ||||
353 | // we will get titi but we want toto-titi | ||||
354 |
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)); | |
355 | } | ||||
356 |
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; | |
357 | 22 | return vInOutArgument; | |||
358 | } | ||||
359 | |||||
360 | 4 | std::string m_getCmdLineHelp() const { | |||
361 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | std::stringstream ss; | |
362 |
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; | |
363 |
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) { |
364 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | ss << " ["; | |
365 | 12 | size_t idx = 0; | |||
366 |
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) { |
367 |
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) { | |
368 |
1/1✓ Branch 1 taken 6 times.
|
1/1✓ Call 0 invoked.
|
6 | ss << ':'; | |
369 | } | ||||
370 |
1/1✓ Branch 1 taken 18 times.
|
1/1✓ Call 0 invoked.
|
18 | ss << o; | |
371 | } | ||||
372 |
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()) { |
373 |
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; | |
374 | } | ||||
375 |
1/1✓ Branch 1 taken 12 times.
|
1/1✓ Call 0 invoked.
|
12 | ss << "]"; | |
376 | } | ||||
377 |
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) { |
378 |
0/1✗ Call 0 not invoked.
|
✗ | std::string token = arg.m_help_var_name; | ||
379 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
0/1✗ Call 0 not invoked.
|
✗ | if (token.empty()) { | |
380 |
0/3✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
|
✗ | token = *(arg.m_base_args.begin()); | ||
381 | } | ||||
382 |
0/2✗ Call 0 not invoked.
✗ Call 3 not invoked.
|
✗ | ss << " " << token; | ||
383 | } | ||||
384 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
8 | return ss.str(); | |
385 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
4 | } | ||
386 | |||||
387 | 4 | std::string m_getHelpDetails( // | |||
388 | const std::string &vPositionalHeader, | ||||
389 | const std::string &vOptionalHeader) const { | ||||
390 | // collect infos with padding | ||||
391 | 4 | size_t first_col_size = 0U; | |||
392 |
1/1✓ Call 0 invoked.
|
4 | std::vector<Argument::HelpCnt> cnt_pos; | ||
393 |
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) { |
394 |
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)); | ||
395 | } | ||||
396 |
1/1✓ Call 0 invoked.
|
4 | std::vector<Argument::HelpCnt> cnt_opt; | ||
397 |
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) { |
398 |
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)); | |
399 | } | ||||
400 | // display | ||||
401 | 4 | first_col_size += 4U; | |||
402 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | std::stringstream ss; | |
403 |
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()) { |
404 |
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; | ||
405 |
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) { | |
406 |
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; | ||
407 | } | ||||
408 | } | ||||
409 |
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()) { |
410 |
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; | |
411 |
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) { |
412 |
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; | |
413 | } | ||||
414 | } | ||||
415 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
8 | return ss.str(); | |
416 |
3/6✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
|
4 | } | ||
417 | |||||
418 | // remove the first '-' of a token | ||||
419 | 49 | std::string m_trim(const std::string &vToken) { | |||
420 |
1/1✓ Call 0 invoked.
|
49 | auto short_last_minus = vToken.find_first_not_of("-"); | ||
421 |
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) { | |
422 |
1/1✓ Call 0 invoked.
|
49 | return vToken.substr(short_last_minus); | ||
423 | } | ||||
424 |
0/1✗ Call 0 not invoked.
|
✗ | return {}; | ||
425 | } | ||||
426 | |||||
427 | template<typename T> | ||||
428 | 22 | T m_convertString(const std::string &str) const { | |||
429 |
1/1✓ Branch 1 taken 11 times.
|
1/1✓ Call 0 invoked.
|
22 | std::istringstream iss(str); | |
430 |
1/1✓ Call 0 invoked.
|
20 | T value; | ||
431 |
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)) { |
432 |
0/4✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
|
✗ | throw std::runtime_error("Conversion failed"); | ||
433 | } | ||||
434 | 42 | return value; | |||
435 |
1/3✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
|
22 | } | ||
436 | }; | ||||
437 | |||||
438 | template<> | ||||
439 | ✗ | bool Args::m_convertString<bool>(const std::string &str) const { | |||
440 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
0/2✗ Call 0 not invoked.
✗ Call 3 not invoked.
|
✗ | if (str == "true" || str == "1") { | |
441 | ✗ | return true; | |||
442 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
0/2✗ Call 0 not invoked.
✗ Call 3 not invoked.
|
✗ | } else if (str == "false" || str == "0") { | |
443 | ✗ | return false; | |||
444 | } | ||||
445 |
0/4✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
|
✗ | throw std::runtime_error("Invalid boolean string"); | ||
446 | } | ||||
447 | } // namespace ez | ||||
448 |
Directory: | include/ezlibs/ |
---|---|
File: | ezGL/uniforms.hpp |
Date: | 2025-01-29 20:42:40 |
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 | ||||
29 | * will aprse 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: | ezGif.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 154 | 163 | 94.5% |
Functions: | 26 | 26 | 100.0% |
Branches: | 51 | 66 | 77.3% |
Decisions: | 22 | 30 | 73.3% |
Calls: | 121 | 138 | 87.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 | // ezGif is part of the ezLibs project : https://github.com/aiekick/ezLibs.git | ||||
28 | |||||
29 | #include <unordered_map> | ||||
30 | #include <algorithm> | ||||
31 | #include <iostream> | ||||
32 | #include <fstream> | ||||
33 | #include <iomanip> | ||||
34 | #include <cstdint> | ||||
35 | #include <string> | ||||
36 | #include <vector> | ||||
37 | #include <cstdio> | ||||
38 | #include <cmath> | ||||
39 | #include <map> | ||||
40 | |||||
41 | namespace ez { | ||||
42 | namespace img { | ||||
43 | |||||
44 | // Gif file format : | ||||
45 | // https://www.loc.gov/preservation/digital/formats/fdd/fdd000133.shtml | ||||
46 | // https://www.matthewflickinger.com/lab/whatsinagif/index.html | ||||
47 | // https://www.matthewflickinger.com/lab/whatsinagif/gif_explorer.asp | ||||
48 | |||||
49 | // https://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp | ||||
50 | |||||
51 | class Gif { | ||||
52 | public: | ||||
53 | typedef uint8_t ColorIndex; | ||||
54 | |||||
55 | struct RGB { | ||||
56 | uint8_t r = 0U; | ||||
57 | uint8_t g = 0U; | ||||
58 | uint8_t b = 0U; | ||||
59 | |||||
60 | 4 | RGB() = default; | |||
61 | |||||
62 | 4 | RGB(uint8_t vR, uint8_t vG, uint8_t vB) : r(vR), g(vG), b(vB) { | |||
63 | 4 | } | |||
64 | }; | ||||
65 | |||||
66 | private: | ||||
67 | FILE *mp_file = nullptr; | ||||
68 | int32_t m_LastError = 0; | ||||
69 | uint16_t m_width = 0U; | ||||
70 | uint16_t m_height = 0U; | ||||
71 | uint8_t m_minCodeSize = 0U; | ||||
72 | std::map<ColorIndex, RGB> m_colors; | ||||
73 | std::vector<ColorIndex> m_pixels; | ||||
74 | |||||
75 | public: | ||||
76 | 1 | Gif& setSize(uint16_t vWidth, uint16_t vHeight) { | |||
77 | 1 | m_width = vWidth; | |||
78 | 1 | m_height = vHeight; | |||
79 | // todo : il faudra sauver les pixel | ||||
80 | // avant resize et transferer apres | ||||
81 |
1/1✓ Call 0 invoked.
|
1 | m_pixels.resize(m_width * m_height); | ||
82 | 1 | return *this; | |||
83 | } | ||||
84 | |||||
85 | 4 | Gif &addColor(ColorIndex vIndex, const RGB &vColor) { | |||
86 |
1/1✓ Call 0 invoked.
|
4 | m_colors[vIndex] = vColor; | ||
87 | 4 | return *this; | |||
88 | } | ||||
89 | |||||
90 | 10000 | Gif &addPixel(uint16_t vX, uint16_t vY, ColorIndex vIndex) { | |||
91 |
1/1✓ Call 0 invoked.
|
10000 | m_pixels[vY * m_width + vX] = vIndex; | ||
92 | 10000 | return *this; | |||
93 | } | ||||
94 | |||||
95 | 1 | bool save(const std::string &vFilePathName) { | |||
96 |
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 (vFilePathName.empty()) { |
97 | ✗ | return false; | |||
98 | } | ||||
99 | #ifdef _MSC_VER | ||||
100 | #else | ||||
101 | #endif | ||||
102 |
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)) { |
103 |
1/1✓ Call 0 invoked.
|
1 | m_writeHeader(); | ||
104 |
1/1✓ Call 0 invoked.
|
1 | m_writeLogicalScreenDescriptor(); | ||
105 |
1/1✓ Call 0 invoked.
|
1 | m_writeGlobalColorTable(); | ||
106 |
1/1✓ Call 0 invoked.
|
1 | m_writeGraphicControlExtension(); | ||
107 |
1/1✓ Call 0 invoked.
|
1 | m_writeImageDescriptor(); | ||
108 |
1/1✓ Call 0 invoked.
|
1 | m_writeImageData(); | ||
109 |
1/1✓ Call 0 invoked.
|
1 | m_writeTrailer(); | ||
110 |
1/1✓ Call 0 invoked.
|
1 | m_closeFile(); | ||
111 | } | ||||
112 | 1 | return true; | |||
113 | } | ||||
114 | |||||
115 | private: | ||||
116 | 1 | bool m_openFileForWriting(const std::string &vFilePathName) { | |||
117 | #if _MSC_VER | ||||
118 | m_LastError = fopen_s(&mp_file, vFilePathName.c_str(), "wb"); | ||||
119 | #else | ||||
120 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | mp_file = fopen(vFilePathName.c_str(), "wb"); | ||
121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | m_LastError = mp_file ? 0 : errno; | ||
122 | #endif | ||||
123 | 1 | return (m_LastError == 0); | |||
124 | } | ||||
125 | |||||
126 | 1 | void m_closeFile() { | |||
127 |
1/1✓ Call 0 invoked.
|
1 | fclose(mp_file); | ||
128 | 1 | } | |||
129 | |||||
130 | 1 | void m_writeHeader() { | |||
131 |
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 | m_writerString("GIF89a"); | |
132 | 1 | } | |||
133 | |||||
134 | 1 | void m_writeLogicalScreenDescriptor() { | |||
135 |
1/1✓ Call 0 invoked.
|
1 | m_writeShort(m_width); // width | ||
136 |
1/1✓ Call 0 invoked.
|
1 | m_writeShort(m_height); // height | ||
137 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x91); // packed field. to detail in few times | ||
138 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0); // bg color index | ||
139 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0); // pixel aspect ratio | ||
140 | 1 | } | |||
141 | |||||
142 | 1 | void m_writeGlobalColorTable() { | |||
143 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | auto bits_count = m_getBitsCount(m_colors.size()); | ||
144 | 1 | m_minCodeSize = static_cast<uint8_t>(bits_count); | |||
145 |
1/1✓ Call 0 invoked.
|
1 | auto colorCount = m_getMaxNumForBitCount(bits_count); | ||
146 | // colors | ||||
147 |
2/2✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 1 times.
|
4/4✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
|
5 | for (const auto &color : m_colors) { |
148 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | m_writeByte(color.second.r); | |
149 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | m_writeByte(color.second.g); | |
150 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | m_writeByte(color.second.b); | |
151 |
1/1✓ Call 0 invoked.
|
4 | --colorCount; | ||
152 | } | ||||
153 | // padding | ||||
154 |
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 | for (size_t idx = 0; idx < colorCount; ++idx) { | |
155 |
1/1✓ Call 0 invoked.
|
4 | m_writeByte(0x00); | ||
156 |
1/1✓ Call 0 invoked.
|
4 | m_writeByte(0x00); | ||
157 |
1/1✓ Call 0 invoked.
|
4 | m_writeByte(0x00); | ||
158 | } | ||||
159 | 1 | } | |||
160 | |||||
161 | 1 | void m_writeGraphicControlExtension() { | |||
162 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x21); // always 21 | ||
163 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0xF9); // always F9 | ||
164 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x04); // byte size | ||
165 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x00); // packed field | ||
166 |
1/1✓ Call 0 invoked.
|
1 | m_writeShort(0x0000); // delay time | ||
167 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x00); // transparent color index | ||
168 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x00); // always 0 | ||
169 | 1 | } | |||
170 | |||||
171 | 1 | void m_writeImageDescriptor() { | |||
172 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x2C); // always 2C | ||
173 |
1/1✓ Call 0 invoked.
|
1 | m_writeShort(0x0000); // image left | ||
174 |
1/1✓ Call 0 invoked.
|
1 | m_writeShort(0x0000); // image top | ||
175 |
1/1✓ Call 0 invoked.
|
1 | m_writeShort(10); // image width | ||
176 |
1/1✓ Call 0 invoked.
|
1 | m_writeShort(10); // image height | ||
177 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x00); // packed field | ||
178 | 1 | } | |||
179 | |||||
180 | 1 | void m_writeImageData() { | |||
181 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(m_minCodeSize); | ||
182 |
1/1✓ Call 0 invoked.
|
1 | m_writeCodeTable(); | ||
183 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x00); // Bloc de terminaison pour l'image | ||
184 | 1 | } | |||
185 | |||||
186 | 1 | static size_t m_getBitsCount(size_t vValue) { | |||
187 | 1 | return (size_t)std::floor(log2((double)vValue)) + 1; | |||
188 | } | ||||
189 | |||||
190 | 1 | static size_t m_getMaxNumForBitCount(size_t vValue) { | |||
191 | 1 | return (1ULL << vValue); | |||
192 | } | ||||
193 | |||||
194 | 1 | void m_writeCodeTable() { | |||
195 | // m_writeCodeTableHeader(); | ||||
196 |
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 | m_writeCompressedData(m_compress(m_pixels)); | |
197 | 1 | } | |||
198 | |||||
199 | 2 | uint8_t m_getClearCode() const { | |||
200 | 2 | return 1 << m_minCodeSize; | |||
201 | } | ||||
202 | |||||
203 | 1 | uint8_t m_getEndOfInfoCode() const { | |||
204 |
1/1✓ Call 0 invoked.
|
1 | return m_getClearCode() + 1; | ||
205 | } | ||||
206 | |||||
207 | void m_writeCodeTableHeader() { | ||||
208 | auto colorCount = m_getMaxNumForBitCount(m_minCodeSize); | ||||
209 | // colors | ||||
210 | for (const auto &color_index : m_colors) { | ||||
211 | m_writeByte(color_index.first); | ||||
212 | --colorCount; | ||||
213 | } | ||||
214 | // colors padding | ||||
215 | for (size_t idx = 0; idx < colorCount; ++idx) { | ||||
216 | m_writeByte(static_cast<uint8_t>(m_colors.size() + idx)); | ||||
217 | } | ||||
218 | // clear code | ||||
219 | m_writeByte(m_getClearCode()); | ||||
220 | // end of information code | ||||
221 | m_writeByte(m_getEndOfInfoCode()); | ||||
222 | } | ||||
223 | |||||
224 | 1 | void m_writeTrailer() { | |||
225 |
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x3B); | ||
226 | 1 | } | |||
227 | |||||
228 | 1 | void m_writeBuffer(const std::vector<uint8_t> &vBuffer, size_t vOffset = 0, size_t vMaxSize = 0) { | |||
229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
|
1 | if (!vMaxSize) { | |
230 |
0/1✗ Call 0 not invoked.
|
✗ | vMaxSize = vBuffer.size(); | ||
231 | } | ||||
232 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | fwrite(&vBuffer.at(vOffset), sizeof(uint8_t), vMaxSize, mp_file); | ||
233 | 1 | } | |||
234 | |||||
235 | 1 | void m_writerString(const std::string &vValue) { | |||
236 |
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
1 | fwrite(vValue.c_str(), sizeof(uint8_t), vValue.size(), mp_file); | ||
237 | 1 | } | |||
238 | |||||
239 | 54 | void m_writeByte(uint8_t vValue) { | |||
240 |
1/1✓ Call 0 invoked.
|
54 | fputc(vValue, mp_file); | ||
241 | std::cout << "write " | ||||
242 |
11/11✓ 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.
✓ Call 9 invoked.
✓ Call 10 invoked.
|
54 | << "0x" << std::setfill('0') << std::setw(2) << std::right << std::uppercase << std::hex << (int32_t)vValue << std::endl; | ||
243 | 54 | } | |||
244 | |||||
245 | 7 | void m_writeShort(uint16_t vValue) { | |||
246 |
1/1✓ Call 0 invoked.
|
7 | m_writeByte(vValue & 0xFF); | ||
247 |
1/1✓ Call 0 invoked.
|
7 | m_writeByte((vValue >> 8) & 0xFF); | ||
248 | 7 | } | |||
249 | |||||
250 | 1 | std::vector<uint16_t> m_compress(const std::vector<uint8_t> &vDatas) { | |||
251 |
1/1✓ Call 0 invoked.
|
1 | std::vector<uint16_t> result; | ||
252 |
1/1✓ Branch 2 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | result.push_back(m_getClearCode()); | |
253 |
1/1✓ Call 0 invoked.
|
1 | std::map<std::vector<uint16_t>, uint16_t> dico; | ||
254 |
2/2✓ Branch 0 taken 256 times.
✓ Branch 1 taken 1 times.
|
2/2✓ Decision 'true' taken 256 times.
✓ Decision 'false' taken 1 times.
|
257 | for (uint16_t i = 0; i < 256; ++i) { | |
255 |
2/2✓ Branch 1 taken 256 times.
✓ Branch 4 taken 256 times.
|
3/4✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 6 invoked.
✗ Call 7 not invoked.
|
768 | dico[{i}] = i; | |
256 | } | ||||
257 | 1 | uint16_t code = 256U; | |||
258 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | uint16_t c = vDatas.at(0); | |
259 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
2 | std::vector<uint16_t> p{c}; | |
260 |
1/1✓ Call 0 invoked.
|
1 | std::vector<uint16_t> pc; | ||
261 |
2/2✓ Branch 1 taken 9999 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 9999 times.
✓ Decision 'false' taken 1 times.
|
1/1✓ Call 0 invoked.
|
10000 | for (size_t idx = 1; idx < vDatas.size(); ++idx) { |
262 |
1/1✓ Branch 1 taken 9999 times.
|
1/1✓ Call 0 invoked.
|
9999 | c = vDatas.at(idx); | |
263 |
1/1✓ Branch 1 taken 9999 times.
|
1/1✓ Call 0 invoked.
|
9999 | pc = p; | |
264 |
1/1✓ Branch 1 taken 9999 times.
|
1/1✓ Call 0 invoked.
|
9999 | pc.push_back(c); | |
265 |
3/3✓ Branch 2 taken 9999 times.
✓ Branch 5 taken 9504 times.
✓ Branch 6 taken 495 times.
|
2/2✓ Decision 'true' taken 9504 times.
✓ Decision 'false' taken 495 times.
|
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 4 invoked.
|
9999 | if (dico.find(pc) != dico.end()) { |
266 |
1/1✓ Branch 1 taken 9504 times.
|
1/1✓ Call 0 invoked.
|
9504 | p.push_back(c); | |
267 | } else { | ||||
268 |
2/2✓ Branch 1 taken 495 times.
✓ Branch 4 taken 495 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
495 | result.push_back(dico.at(p)); | |
269 |
1/1✓ Branch 1 taken 495 times.
|
1/1✓ Call 0 invoked.
|
495 | dico[pc] = code++; | |
270 |
1/1✓ Branch 1 taken 495 times.
|
1/1✓ Call 0 invoked.
|
495 | p = {c}; | |
271 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 495 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 495 times.
|
495 | if (code >= 4096) { | |
272 |
0/2✗ Call 0 not invoked.
✗ Call 1 not invoked.
|
✗ | result.push_back(m_getClearCode()); | ||
273 |
0/1✗ Call 0 not invoked.
|
✗ | dico.clear(); | ||
274 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | for (uint16_t i = 0; i < 256; ++i) { | ||
275 |
0/4✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
|
✗ | dico[{i}] = i; | ||
276 | } | ||||
277 | ✗ | code = 258; | |||
278 | } | ||||
279 | } | ||||
280 | } | ||||
281 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
1 | result.push_back(dico.at(p)); | |
282 |
1/1✓ Branch 2 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | result.push_back(m_getEndOfInfoCode()); | |
283 | 2 | return result; | |||
284 |
3/7✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✗ Call 3 not invoked.
✗ Call 4 not invoked.
✗ Call 5 not invoked.
✗ Call 6 not invoked.
|
1 | } | ||
285 | |||||
286 | 1 | void m_writeCompressedData(const std::vector<uint16_t> &compressedData) { | |||
287 | 1 | uint8_t bitBuffer = 0; // Buffer de bits pour l'�criture des octets | |||
288 | 1 | int bitCount = 0; // Nombre de bits accumul�s dans le buffer | |||
289 | 1 | uint8_t currentCodeSize = m_minCodeSize + 1; // Taille actuelle des codes | |||
290 | |||||
291 |
1/1✓ Call 0 invoked.
|
1 | std::vector<uint8_t> outputBytes; | ||
292 | |||||
293 |
2/2✓ Branch 5 taken 498 times.
✓ Branch 6 taken 1 times.
|
2/2✓ Decision 'true' taken 498 times.
✓ Decision 'false' taken 1 times.
|
5/5✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
499 | for (auto code : compressedData) { |
294 | // Ajouter le code au buffer de bits | ||||
295 | 498 | bitBuffer |= (code << bitCount); | |||
296 | 498 | bitCount += currentCodeSize; | |||
297 | |||||
298 | // �crire les octets entiers dans le buffer jusqu'� ce qu'on n'ait plus de 8 bits | ||||
299 |
2/2✓ Branch 0 taken 249 times.
✓ Branch 1 taken 498 times.
|
2/2✓ Decision 'true' taken 249 times.
✓ Decision 'false' taken 498 times.
|
747 | while (bitCount >= 8) { | |
300 |
1/1✓ Branch 1 taken 249 times.
|
1/1✓ Call 0 invoked.
|
249 | outputBytes.push_back(bitBuffer & 0xFF); // �crire le byte entier | |
301 | 249 | bitBuffer >>= 8; // D�caler le buffer vers la droite de 8 bits | |||
302 | 249 | bitCount -= 8; | |||
303 | } | ||||
304 | |||||
305 | // Augmenter la taille des codes au fur et � mesure que le dictionnaire grandit | ||||
306 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 498 times.
|
498 | if (code == (1 << currentCodeSize) - 1 && currentCodeSize < 12) { | |
307 | ✗ | ++currentCodeSize; | |||
308 | } | ||||
309 | } | ||||
310 | |||||
311 | // �crire les bits restants dans le buffer (si non vide) | ||||
312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
|
1 | if (bitCount > 0) { | |
313 |
0/1✗ Call 0 not invoked.
|
✗ | outputBytes.push_back(bitBuffer & 0xFF); | ||
314 | } | ||||
315 | |||||
316 | // �crire les donn�es en blocs de 255 octets maximum | ||||
317 | 1 | size_t index = 0; | |||
318 |
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 | while (index < outputBytes.size()) { |
319 |
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | size_t blockSize = std::min(size_t(255), outputBytes.size() - index); | ||
320 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_writeByte(static_cast<uint8_t>(blockSize)); // Taille du bloc | |
321 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_writeBuffer(outputBytes, index, blockSize); | |
322 | 1 | index += blockSize; | |||
323 | } | ||||
324 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_writeByte(0x00); // Bloc de terminaison pour l'image | |
325 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
1 | } | ||
326 | }; | ||||
327 | |||||
328 | } // namespace img | ||||
329 | } // namespace ez | ||||
330 |
Directory: | include/ezlibs/ |
---|---|
File: | ezBuildInc.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 128 | 131 | 97.7% |
Functions: | 18 | 18 | 100.0% |
Branches: | 154 | 164 | 93.9% |
Decisions: | 34 | 44 | 77.3% |
Calls: | 204 | 239 | 85.4% |
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 | std::string m_buildFileHeader; | ||||
54 | std::string m_project; | ||||
55 | std::string m_label; | ||||
56 | int32_t m_majorNumber = 0; | ||||
57 | int32_t m_minorNumber = 0; | ||||
58 | int32_t m_buildNumber = 0; | ||||
59 | #ifdef EZ_FIG_FONT | ||||
60 | class FigFontGenerator { | ||||
61 | friend class BuildInc; | ||||
62 | private: | ||||
63 | ez::FigFont m_generator; | ||||
64 | bool m_useLabel = true; // will use the label or not for the FigFont label | ||||
65 | bool m_useBuildNumber = false; // will use the buildNumber or not for the FigFont label | ||||
66 | public: | ||||
67 |
1/1✓ Call 0 invoked.
|
6 | bool isValid() { return m_generator.isValid(); } | ||
68 | 2 | FigFontGenerator& useLabel(const bool vFlag) { | |||
69 | 2 | m_useLabel = vFlag; | |||
70 | 2 | return *this; | |||
71 | } | ||||
72 | 2 | FigFontGenerator& useBuildNumber(const bool vFlag) { | |||
73 | 2 | m_useBuildNumber = vFlag; | |||
74 | 2 | return *this; | |||
75 | } | ||||
76 | } m_figFontGenerator; | ||||
77 | #endif // EZ_FIG_FONT | ||||
78 | |||||
79 | public: | ||||
80 |
4/4✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
✓ Call 3 invoked.
|
1 | BuildInc(const std::string& vBuildFileHeader) { | ||
81 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_buildFileHeader = vBuildFileHeader; | |
82 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | read(); | |
83 |
0/4✗ Call 0 not invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
1 | } | ||
84 | 1 | BuildInc& read() { | |||
85 |
1/1✓ Call 0 invoked.
|
1 | std::string content; | ||
86 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | std::ifstream docFile(m_buildFileHeader, std::ios::in); | |
87 |
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()) { |
88 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | std::stringstream strStream; | |
89 |
1/1✓ Branch 2 taken 1 times.
|
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
1 | strStream << docFile.rdbuf(); | |
90 |
1/1✓ Branch 1 taken 1 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
1 | content = strStream.str(); | |
91 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | docFile.close(); | |
92 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
1 | } | ||
93 |
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()) { |
94 | 1 | size_t startLine = 0; | |||
95 |
1/1✓ Call 0 invoked.
|
1 | size_t endLine = content.find('\n', startLine); | ||
96 |
1/1✓ Call 0 invoked.
|
1 | std::string line; | ||
97 |
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
1 | std::string project, key, value; | ||
98 |
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) { | |
99 |
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); | |
100 |
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)) { |
101 |
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 | |
102 |
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") { |
103 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_label = value; | |
104 |
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") { |
105 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_majorNumber = m_toNumber(value); | |
106 |
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") { |
107 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_minorNumber = m_toNumber(value); | |
108 |
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") { |
109 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | m_buildNumber = m_toNumber(value); | |
110 | } | ||||
111 | } | ||||
112 | 8 | startLine = endLine+1; | |||
113 |
1/1✓ Call 0 invoked.
|
8 | endLine = content.find('\n', startLine); | ||
114 | } | ||||
115 |
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 | } | ||
116 | 1 | return *this; | |||
117 |
2/4✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
1 | } | ||
118 | 4 | std::string getInfos() { | |||
119 |
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; | |
120 |
3/3✓ Call 0 invoked.
✓ Call 1 invoked.
✓ Call 2 invoked.
|
4 | std::string project_str, build_id_str, file_str; | ||
121 |
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; | |
122 |
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(); | |
123 |
1/1✓ Call 0 invoked.
|
4 | size_t row_len = build_id_str.size(); | ||
124 |
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; | |
125 |
1/1✓ Branch 1 taken 4 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
4 | file_str = file.str(); | |
126 |
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()) { |
127 |
0/1✗ Call 0 not invoked.
|
✗ | row_len = file_str.size(); | ||
128 | } | ||||
129 |
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()) { |
130 |
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; | |
131 |
1/1✓ Branch 1 taken 4 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
4 | project_str = project.str(); | |
132 |
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()) { |
133 |
0/1✗ Call 0 not invoked.
|
✗ | row_len = project_str.size(); | ||
134 | } | ||||
135 | } | ||||
136 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | auto spliter = std::string(row_len + 6, '-'); // +6 for '-- ' and ' --' | |
137 |
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; | |
138 |
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()) { |
139 |
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; | |
140 | } | ||||
141 |
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; | |
142 |
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; | |
143 |
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; | |
144 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
8 | return infos.str(); | |
145 |
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 | } | ||
146 | 4 | BuildInc& printInfos() { | |||
147 |
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(); | |
148 | 4 | return *this; | |||
149 | } | ||||
150 | 1 | const std::string& getProject() { return m_project; } | |||
151 | 1 | const std::string& getLabel() { return m_label; } | |||
152 | 1 | int32_t getMajor() { return m_majorNumber; } | |||
153 | 1 | int32_t getMinor() { return m_minorNumber; } | |||
154 | 1 | int32_t getBuildNumber() { return m_buildNumber; } | |||
155 | BuildInc& setProject(const std::string& vProject) { | ||||
156 | m_project = vProject; | ||||
157 | return *this; | ||||
158 | } | ||||
159 | BuildInc& setLabel(const std::string& vLabel) { | ||||
160 | m_label = vLabel; | ||||
161 | return *this; | ||||
162 | } | ||||
163 | BuildInc& setMajor(const int32_t vMajorNumber) { | ||||
164 | m_majorNumber = vMajorNumber; | ||||
165 | return *this; | ||||
166 | } | ||||
167 | BuildInc& setMinor(const int32_t vMinorNumber) { | ||||
168 | m_minorNumber = vMinorNumber; | ||||
169 | return *this; | ||||
170 | } | ||||
171 | BuildInc& setBuildNumber(const int32_t vBuildNumber) { | ||||
172 | m_buildNumber = vBuildNumber; | ||||
173 | return *this; | ||||
174 | } | ||||
175 | 1 | BuildInc& incBuildNumber() { | |||
176 | 1 | ++m_buildNumber; | |||
177 | 1 | return *this; | |||
178 | } | ||||
179 | #ifdef EZ_FIG_FONT | ||||
180 | 2 | FigFontGenerator& setFigFontFile(const std::string& vFigFontFile) { | |||
181 |
1/1✓ Call 0 invoked.
|
2 | m_figFontGenerator.m_generator.load(vFigFontFile); | ||
182 | 2 | return m_figFontGenerator; | |||
183 | } | ||||
184 | #endif // EZ_FIG_FONT | ||||
185 | 4 | BuildInc& write() { | |||
186 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | std::stringstream content; | |
187 |
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; | |
188 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | content << std::endl; | |
189 |
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; | |
190 |
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; | |
191 |
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; | |
192 |
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; | |
193 |
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; | |
194 | #ifdef EZ_FIG_FONT | ||||
195 |
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()) { |
196 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | std::stringstream version; | |
197 |
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) { | |
198 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
2 | version << m_label << " "; | |
199 | } | ||||
200 |
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; | |
201 |
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) { | |
202 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
|
2/2✓ Call 0 invoked.
✓ Call 3 invoked.
|
2 | version << "." << m_buildNumber; | |
203 | } | ||||
204 |
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; | |
205 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
4 | } | ||
206 | #endif // EZ_FIG_FONT | ||||
207 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | std::ofstream configFileWriter(m_buildFileHeader, std::ios::out); | |
208 |
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()) { |
209 |
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(); | |
210 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | configFileWriter.close(); | |
211 | } | ||||
212 | 4 | return *this; | |||
213 |
2/4✓ Call 0 invoked.
✓ Call 1 invoked.
✗ Call 2 not invoked.
✗ Call 3 not invoked.
|
4 | } | ||
214 | |||||
215 | private: | ||||
216 | // will parse a line '#define [PROJECT]_[KEY] [VALUE]' | ||||
217 | // return true is succeed, false if the format is not recognized | ||||
218 | 8 | bool m_parseDefine(const std::string& vRowContent, std::string& vOutProject, std::string& vOutKey, std::string& vOutValue) { | |||
219 |
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()) { |
220 |
1/1✓ Call 0 invoked.
|
6 | size_t def_pos = vRowContent.find("#define "); | ||
221 |
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) { | |
222 | 5 | def_pos += 8; // offset for '#define ' | |||
223 |
1/1✓ Call 0 invoked.
|
5 | size_t underScore_pos = vRowContent.find('_', def_pos); | ||
224 |
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) { | |
225 |
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); | |
226 | 5 | ++underScore_pos; // offset for '_' | |||
227 |
1/1✓ Call 0 invoked.
|
5 | size_t space_pos = vRowContent.find(' ', underScore_pos); | ||
228 |
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) { | |
229 |
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); | |
230 | 5 | ++space_pos; // offset for ' ' | |||
231 |
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)); | |
232 | 5 | return true; | |||
233 | } | ||||
234 | } | ||||
235 | } | ||||
236 | } | ||||
237 | 3 | return false; | |||
238 | } | ||||
239 | 3 | int32_t m_toNumber(const std::string& vNum) { | |||
240 | 3 | int32_t ret = 0; // 0 is the default value | |||
241 | try { | ||||
242 |
1/1✓ Branch 1 taken 3 times.
|
1/1✓ Call 0 invoked.
|
3 | ret = std::stoi(vNum); | |
243 |
0/1✗ Call 0 not invoked.
|
✗ | } catch (...) { | ||
244 | } | ||||
245 | 3 | return ret; | |||
246 | } | ||||
247 | // will remove quotes | ||||
248 | 5 | std::string m_trim(const std::string& vValue) { | |||
249 |
1/1✓ Call 0 invoked.
|
5 | std::string ret; | ||
250 |
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) { |
251 |
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 != '\"') { | |
252 |
1/1✓ Branch 1 taken 21 times.
|
1/1✓ Call 0 invoked.
|
21 | ret += c; | |
253 | } | ||||
254 | } | ||||
255 | 5 | return ret; | |||
256 | } | ||||
257 | }; | ||||
258 | |||||
259 | } // namespace ez | ||||
260 |
Directory: | include/ezlibs/ |
---|---|
File: | ezFile.hpp |
Date: | 2025-01-29 20:42:40 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 24 | 31 | 77.4% |
Functions: | 2 | 2 | 100.0% |
Branches: | 20 | 36 | 55.6% |
Decisions: | 4 | 10 | 40.0% |
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 | #define stat _stat | ||||
46 | #else // UNIX | ||||
47 | #define EZ_FILE_SLASH_TYPE "/" | ||||
48 | #endif | ||||
49 | #endif // EZ_FILE_SLASH_TYPE | ||||
50 | |||||
51 | namespace ez { | ||||
52 | namespace file { | ||||
53 | |||||
54 | 4 | inline std::string loadFileToString(const std::string &vFilePathName) { | |||
55 |
1/1✓ Call 0 invoked.
|
4 | std::string ret; | ||
56 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | std::ifstream docFile(vFilePathName, std::ios::in); | |
57 |
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()) { |
58 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | std::stringstream strStream; | |
59 |
1/1✓ Branch 2 taken 4 times.
|
2/2✓ Call 0 invoked.
✓ Call 1 invoked.
|
4 | strStream << docFile.rdbuf(); // read the file | |
60 |
1/1✓ Branch 1 taken 4 times.
|
3/3✓ Call 0 invoked.
✓ Call 3 invoked.
✓ Call 4 invoked.
|
4 | ret = strStream.str(); | |
61 |
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"); | |
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.
|
12 | ez::str::replaceString(ret, "\r", "\n"); | |
63 |
1/1✓ Branch 1 taken 4 times.
|
1/1✓ Call 0 invoked.
|
4 | docFile.close(); | |
64 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
4 | } else { | ||
65 | #ifdef EZ_TOOLS_LOG | ||||
66 |
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()); | ||
67 | #endif | ||||
68 | } | ||||
69 | 8 | return ret; | |||
70 |
1/3✓ Call 0 invoked.
✗ Call 1 not invoked.
✗ Call 2 not invoked.
|
4 | } | ||
71 | |||||
72 | 1 | inline bool saveStringToFile(const std::string &vDatas, const std::string &vFilePathName, bool vAddTimeStamp = false) { | |||
73 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | std::string fpn = vFilePathName; | |
74 |
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()) { |
75 |
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) { | |
76 |
0/1✗ Call 0 not invoked.
|
✗ | auto dot_p = fpn.find_last_of('.'); | ||
77 |
0/1✗ Call 0 not invoked.
|
✗ | time_t epoch = std::time(nullptr); | ||
78 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (dot_p != std::string::npos) { | ||
79 |
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); | ||
80 | } else { | ||||
81 |
0/4✗ Call 0 not invoked.
✗ Call 3 not invoked.
✗ Call 6 not invoked.
✗ Call 7 not invoked.
|
✗ | fpn += ez::str::toStr("_%llu", epoch); | ||
82 | } | ||||
83 | } | ||||
84 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | std::ofstream configFileWriter(fpn, std::ios::out); | |
85 |
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()) { |
86 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | configFileWriter << vDatas; | |
87 |
1/1✓ Branch 1 taken 1 times.
|
1/1✓ Call 0 invoked.
|
1 | configFileWriter.close(); | |
88 | 1 | return true; | |||
89 | } | ||||
90 |
1/2✓ Call 0 invoked.
✗ Call 3 not invoked.
|
1 | } | ||
91 | ✗ | return false; | |||
92 |
1/2✓ Call 0 invoked.
✗ Call 1 not invoked.
|
1 | } | ||
93 | |||||
94 | inline std::vector<uint8_t> loadFileToBin(const std::string &vFilePathName) { | ||||
95 | std::vector<uint8_t> ret; | ||||
96 | std::ifstream docFile(vFilePathName, std::ios::in | std::ios::binary); | ||||
97 | if (docFile.is_open()) { | ||||
98 | // int32_t because the internal << used by 'istream_iterator' is not defined for uint8_t | ||||
99 | ret = {std::istream_iterator<char>(docFile), std::istream_iterator<char>()}; | ||||
100 | docFile.close(); | ||||
101 | } else { | ||||
102 | #ifdef EZ_TOOLS_LOG | ||||
103 | LogVarError("File \"%s\" Not Found !\n", vFilePathName.c_str()); | ||||
104 | #endif | ||||
105 | } | ||||
106 | return ret; | ||||
107 | } | ||||
108 | |||||
109 | inline bool saveBinToFile(const std::vector<uint8_t> &vDatas, const std::string &vFilePathName, bool vAddTimeStamp = false) { | ||||
110 | std::string fpn = vFilePathName; | ||||
111 | if (!fpn.empty()) { | ||||
112 | if (vAddTimeStamp) { | ||||
113 | auto dot_p = fpn.find_last_of('.'); | ||||
114 | time_t epoch = std::time(nullptr); | ||||
115 | if (dot_p != std::string::npos) { | ||||
116 | fpn = fpn.substr(0, dot_p) + ez::str::toStr("_%llu", epoch) + fpn.substr(dot_p); | ||||
117 | } else { | ||||
118 | fpn += ez::str::toStr("_%llu", epoch); | ||||
119 | } | ||||
120 | } | ||||
121 | std::ofstream out(fpn, std::ios::out | std::ios::binary); | ||||
122 | if (!out.bad()) { | ||||
123 | out.write(reinterpret_cast<const char *>(vDatas.data()), vDatas.size()); | ||||
124 | out.close(); | ||||
125 | return true; | ||||
126 | } | ||||
127 | } | ||||
128 | return false; | ||||
129 | } | ||||
130 | |||||
131 | /* correct file path between os and different slash type between window and unix */ | ||||
132 | inline std::string correctSlashTypeForFilePathName(const std::string &vFilePathName) { | ||||
133 | std::string res = vFilePathName; | ||||
134 | ez::str::replaceString(res, "\\", EZ_FILE_SLASH_TYPE); | ||||
135 | ez::str::replaceString(res, "/", EZ_FILE_SLASH_TYPE); | ||||
136 | return res; | ||||
137 | } | ||||
138 | |||||
139 | struct PathInfos { | ||||
140 | std::string path; | ||||
141 | std::string name; | ||||
142 | std::string ext; | ||||
143 | bool isOk = false; | ||||
144 | |||||
145 | PathInfos() { | ||||
146 | isOk = false; | ||||
147 | } | ||||
148 | |||||
149 | PathInfos(const std::string &vPath, const std::string &vName, const std::string &vExt) { | ||||
150 | isOk = true; | ||||
151 | path = vPath; | ||||
152 | name = vName; | ||||
153 | ext = vExt; | ||||
154 | |||||
155 | if (ext.empty()) { | ||||
156 | const size_t lastPoint = name.find_last_of('.'); | ||||
157 | if (lastPoint != std::string::npos) { | ||||
158 | ext = name.substr(lastPoint + 1); | ||||
159 | name = name.substr(0, lastPoint); | ||||
160 | } | ||||
161 | } | ||||
162 | } | ||||
163 | |||||
164 | std::string GetFPNE() { | ||||
165 | return GetFPNE_WithPathNameExt(path, name, ext); | ||||
166 | } | ||||
167 | |||||
168 | std::string GetFPNE_WithPathNameExt(std::string vPath, const std::string &vName, const std::string &vExt) { | ||||
169 | if (vPath[0] == EZ_FILE_SLASH_TYPE[0]) { | ||||
170 | #ifdef WIN32 | ||||
171 | // if it happening on window this seem that this path msut be a relative path but with an error | ||||
172 | vPath = vPath.substr(1); // bad formated path go relative | ||||
173 | #endif | ||||
174 | } else { | ||||
175 | #ifdef UNIX | ||||
176 | vPath = "/" + vPath; // make it absolute | ||||
177 | #endif | ||||
178 | } | ||||
179 | |||||
180 | if (vPath.empty()) return vName + "." + vExt; | ||||
181 | |||||
182 | return vPath + EZ_FILE_SLASH_TYPE + vName + "." + vExt; | ||||
183 | } | ||||
184 | |||||
185 | std::string GetFPNE_WithPath(const std::string &vPath) { | ||||
186 | return GetFPNE_WithPathNameExt(vPath, name, ext); | ||||
187 | } | ||||
188 | |||||
189 | std::string GetFPNE_WithPathName(const std::string &vPath, const std::string &vName) { | ||||
190 | return GetFPNE_WithPathNameExt(vPath, vName, ext); | ||||
191 | } | ||||
192 | |||||
193 | std::string GetFPNE_WithPathExt(const std::string &vPath, const std::string &vExt) { | ||||
194 | return GetFPNE_WithPathNameExt(vPath, name, vExt); | ||||
195 | } | ||||
196 | |||||
197 | std::string GetFPNE_WithName(const std::string &vName) { | ||||
198 | return GetFPNE_WithPathNameExt(path, vName, ext); | ||||
199 | } | ||||
200 | |||||
201 | std::string GetFPNE_WithNameExt(const std::string &vName, const std::string &vExt) { | ||||
202 | return GetFPNE_WithPathNameExt(path, vName, vExt); | ||||
203 | } | ||||
204 | |||||
205 | std::string GetFPNE_WithExt(const std::string &vExt) { | ||||
206 | return GetFPNE_WithPathNameExt(path, name, vExt); | ||||
207 | } | ||||
208 | }; | ||||
209 | |||||
210 | inline PathInfos parsePathFileName(const std::string &vPathFileName) { | ||||
211 | PathInfos res; | ||||
212 | if (!vPathFileName.empty()) { | ||||
213 | const std::string pfn = correctSlashTypeForFilePathName(vPathFileName); | ||||
214 | if (!pfn.empty()) { | ||||
215 | const size_t lastSlash = pfn.find_last_of(EZ_FILE_SLASH_TYPE); | ||||
216 | if (lastSlash != std::string::npos) { | ||||
217 | res.name = pfn.substr(lastSlash + 1); | ||||
218 | res.path = pfn.substr(0, lastSlash); | ||||
219 | res.isOk = true; | ||||
220 | } | ||||
221 | const size_t lastPoint = pfn.find_last_of('.'); | ||||
222 | if (lastPoint != std::string::npos) { | ||||
223 | if (!res.isOk) { | ||||
224 | res.name = pfn; | ||||
225 | res.isOk = true; | ||||
226 | } | ||||
227 | res.ext = pfn.substr(lastPoint + 1); | ||||
228 | ez::str::replaceString(res.name, "." + res.ext, ""); | ||||
229 | } | ||||
230 | if (!res.isOk) { | ||||
231 | res.name = pfn; | ||||
232 | res.isOk = true; | ||||
233 | } | ||||
234 | } | ||||
235 | } | ||||
236 | return res; | ||||
237 | } | ||||
238 | |||||
239 | inline std::string simplifyFilePath(const std::string &vFilePath) { | ||||
240 | std::string newPath = correctSlashTypeForFilePathName(vFilePath); | ||||
241 | // the idea is to simplify a path where there is some .. | ||||
242 | // by ex : script\\kifs\\../space3d.glsl => can be simplified in /script/space3d.glsl | ||||
243 | size_t dpt = 0; | ||||
244 | while ((dpt = newPath.find("..")) != std::string::npos) { | ||||
245 | ez::str::replaceString(newPath, "\\", EZ_FILE_SLASH_TYPE); | ||||
246 | ez::str::replaceString(newPath, "/", EZ_FILE_SLASH_TYPE); | ||||
247 | size_t sl = newPath.rfind(EZ_FILE_SLASH_TYPE, dpt); | ||||
248 | if (sl != std::string::npos) { | ||||
249 | if (sl > 0) { | ||||
250 | sl = newPath.rfind(EZ_FILE_SLASH_TYPE, sl - 1); | ||||
251 | if (sl != std::string::npos) { | ||||
252 | std::string str = newPath.substr(sl, dpt + 2 - sl); | ||||
253 | ez::str::replaceString(newPath, str, ""); | ||||
254 | } | ||||
255 | } | ||||
256 | } else { | ||||
257 | break; | ||||
258 | } | ||||
259 | } | ||||
260 | return newPath; | ||||
261 | } | ||||
262 | |||||
263 | inline std::string composePath(const std::string &vPath, const std::string &vFileName, const std::string &vExt) { | ||||
264 | const auto path = correctSlashTypeForFilePathName(vPath); | ||||
265 | std::string res = path; | ||||
266 | if (!vFileName.empty()) { | ||||
267 | if (!path.empty()) { | ||||
268 | res += EZ_FILE_SLASH_TYPE; | ||||
269 | } | ||||
270 | res += vFileName; | ||||
271 | if (!vExt.empty()) { | ||||
272 | res += "." + vExt; | ||||
273 | } | ||||
274 | } | ||||
275 | return res; | ||||
276 | } | ||||
277 | |||||
278 | inline bool isFileExist(const std::string &name) { | ||||
279 | auto fileToOpen = correctSlashTypeForFilePathName(name); | ||||
280 | ez::str::replaceString(fileToOpen, "\"", ""); | ||||
281 | ez::str::replaceString(fileToOpen, "\n", ""); | ||||
282 | ez::str::replaceString(fileToOpen, "\r", ""); | ||||
283 | std::ifstream docFile(fileToOpen, std::ios::in); | ||||
284 | if (docFile.is_open()) { | ||||
285 | docFile.close(); | ||||
286 | return true; | ||||
287 | } | ||||
288 | return false; | ||||
289 | } | ||||
290 | |||||
291 | inline bool isDirectoryExist(const std::string &name) { | ||||
292 | if (!name.empty()) { | ||||
293 | const std::string dir = correctSlashTypeForFilePathName(name); | ||||
294 | struct stat sb; | ||||
295 | if (stat(dir.c_str(), &sb)) { | ||||
296 | return (sb.st_mode & S_IFDIR); | ||||
297 | } | ||||
298 | } | ||||
299 | return false; | ||||
300 | } | ||||
301 | |||||
302 | inline bool destroyFile(const std::string &vFilePathName) { | ||||
303 | if (!vFilePathName.empty()) { | ||||
304 | const auto filePathName = correctSlashTypeForFilePathName(vFilePathName); | ||||
305 | if (isFileExist(filePathName)) { | ||||
306 | if (remove(filePathName.c_str()) == 0) { | ||||
307 | return true; | ||||
308 | } | ||||
309 | } | ||||
310 | } | ||||
311 | return false; | ||||
312 | } | ||||
313 | |||||
314 | inline bool createDirectoryIfNotExist(const std::string &name) { | ||||
315 | bool res = false; | ||||
316 | if (!name.empty()) { | ||||
317 | const auto filePathName = correctSlashTypeForFilePathName(name); | ||||
318 | if (!isDirectoryExist(filePathName)) { | ||||
319 | res = true; | ||||
320 | #ifdef WIN32 | ||||
321 | CreateDirectory(filePathName.c_str(), nullptr); | ||||
322 | #elif defined(UNIX) | ||||
323 | auto cmd = ez::str::toStr("mkdir -p %s", filePathName.c_str()); | ||||
324 | const int dir_err = std::system(cmd.c_str()); | ||||
325 | if (dir_err == -1) { | ||||
326 | LogVarError("Error creating directory %s", filePathName.c_str()); | ||||
327 | res = false; | ||||
328 | } | ||||
329 | #endif | ||||
330 | } | ||||
331 | } | ||||
332 | return res; | ||||
333 | } | ||||
334 | |||||
335 | inline bool createPathIfNotExist(const std::string &vPath) { | ||||
336 | bool res = false; | ||||
337 | if (!vPath.empty()) { | ||||
338 | auto path = correctSlashTypeForFilePathName(vPath); | ||||
339 | if (!isDirectoryExist(path)) { | ||||
340 | res = true; | ||||
341 | ez::str::replaceString(path, "/", "|"); | ||||
342 | ez::str::replaceString(path, "\\", "|"); | ||||
343 | auto arr = ez::str::splitStringToVector(path, "|"); | ||||
344 | std::string fullPath; | ||||
345 | for (auto it = arr.begin(); it != arr.end(); ++it) { | ||||
346 | fullPath += *it; | ||||
347 | res &= createDirectoryIfNotExist(fullPath); | ||||
348 | fullPath += EZ_FILE_SLASH_TYPE; | ||||
349 | } | ||||
350 | } | ||||
351 | } | ||||
352 | return res; | ||||
353 | } | ||||
354 | |||||
355 | // will open the file is the associated app | ||||
356 | inline void openFile(const std::string &vFile) { | ||||
357 | const auto file = correctSlashTypeForFilePathName(vFile); | ||||
358 | #if defined(WIN32) | ||||
359 | auto *result = ShellExecute(nullptr, "", file.c_str(), nullptr, nullptr, SW_SHOW); | ||||
360 | if (result < (HINSTANCE)32) { //-V112 | ||||
361 | // try to open an editor | ||||
362 | result = ShellExecute(nullptr, "edit", file.c_str(), nullptr, nullptr, SW_SHOW); | ||||
363 | if (result == (HINSTANCE)SE_ERR_ASSOCINCOMPLETE || result == (HINSTANCE)SE_ERR_NOASSOC) { | ||||
364 | // open associating dialog | ||||
365 | const std::string sCmdOpenWith = "shell32.dll,OpenAs_RunDLL \"" + file + "\""; | ||||
366 | result = ShellExecute(nullptr, "", "rundll32.exe", sCmdOpenWith.c_str(), nullptr, SW_NORMAL); | ||||
367 | } | ||||
368 | if (result < (HINSTANCE)32) { // open in explorer //-V112 | ||||
369 | const std::string sCmdExplorer = "/select,\"" + file + "\""; | ||||
370 | ShellExecute( | ||||
371 | nullptr, "", "explorer.exe", sCmdExplorer.c_str(), nullptr, SW_NORMAL); // ce serait peut etre mieu d'utilsier la commande system comme dans SelectFile | ||||
372 | } | ||||
373 | } | ||||
374 | #elif defined(LINUX) | ||||
375 | int pid = fork(); | ||||
376 | if (pid == 0) { | ||||
377 | execl("/usr/bin/xdg-open", "xdg-open", file.c_str(), (char *)0); | ||||
378 | } | ||||
379 | #elif defined(APPLE) | ||||
380 | std::string cmd = "open " + file; | ||||
381 | std::system(cmd.c_str()); | ||||
382 | #endif | ||||
383 | } | ||||
384 | |||||
385 | // will open the url in the related browser | ||||
386 | inline void openUrl(const std::string &vUrl) { | ||||
387 | const auto url = correctSlashTypeForFilePathName(vUrl); | ||||
388 | #ifdef WIN32 | ||||
389 | ShellExecute(nullptr, nullptr, url.c_str(), nullptr, nullptr, SW_SHOW); | ||||
390 | #elif defined(LINUX) | ||||
391 | auto cmd = ez::str::toStr("<mybrowser> %s", url.c_str()); | ||||
392 | std::system(cmd.c_str()); | ||||
393 | #elif defined(APPLE) | ||||
394 | // std::string sCmdOpenWith = "open -a Firefox " + vUrl; | ||||
395 | std::string cmd = "open " + url; | ||||
396 | std::system(cmd.c_str()); | ||||
397 | #endif | ||||
398 | } | ||||
399 | |||||
400 | // will open the current file explorer and will select the file | ||||
401 | inline void selectFile(const std::string &vFileToSelect) { | ||||
402 | const auto fileToSelect = correctSlashTypeForFilePathName(vFileToSelect); | ||||
403 | #ifdef WIN32 | ||||
404 | if (!fileToSelect.empty()) { | ||||
405 | const std::string sCmdOpenWith = "explorer /select," + fileToSelect; | ||||
406 | std::system(sCmdOpenWith.c_str()); | ||||
407 | } | ||||
408 | #elif defined(LINUX) | ||||
409 | // todo : is there a similar cmd on linux ? | ||||
410 | assert(nullptr); | ||||
411 | #elif defined(APPLE) | ||||
412 | if (!fileToSelect.empty()) { | ||||
413 | std::string cmd = "open -R " + fileToSelect; | ||||
414 | std::system(cmd.c_str()); | ||||
415 | } | ||||
416 | #endif | ||||
417 | } | ||||
418 | |||||
419 | inline std::vector<std::string> getDrives() { | ||||
420 | std::vector<std::string> res; | ||||
421 | #ifdef WIN32 | ||||
422 | const DWORD mydrives = 2048; | ||||
423 | char lpBuffer[2048]; | ||||
424 | const DWORD countChars = GetLogicalDriveStrings(mydrives, lpBuffer); | ||||
425 | if (countChars > 0) { | ||||
426 | std::string var = std::string(lpBuffer, (size_t)countChars); | ||||
427 | ez::str::replaceString(var, "\\", ""); | ||||
428 | res = ez::str::splitStringToVector(var, "\0"); | ||||
429 | } | ||||
430 | #else | ||||
431 | assert(nullptr); | ||||
432 | #endif | ||||
433 | return res; | ||||
434 | } | ||||
435 | |||||
436 | } // namespace file | ||||
437 | } // namespace ez | ||||
438 |