GCC Code Coverage Report


Directory: include/ezlibs/
Date: 2025-01-29 20:42:40
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Exec Total Coverage
Lines: 3024 3215 94.1%
Functions: 971 986 98.5%
Branches: 2198 2649 83.0%
Decisions: 629 820 76.7%
Calls: 3373 4241 79.5%

Overall list of functions

File Lines Functions Branches Decisions Calls
ezAABBCC.hpp 100.0 100.0% 23 / 23 100.0% 5 / 5 -% 0 / 0 -% 0 / 0 100.0% 19 / 19
ezArgs.hpp 86.3 86.3% 202 / 234 96.0% 24 / 25 72.1% 194 / 269 75.4% 95 / 126 64.6% 250 / 387
ezBmp.hpp 94.3 94.3% 50 / 53 100.0% 6 / 6 72.7% 16 / 22 66.7% 8 / 12 80.0% 20 / 25
ezBuildInc.hpp 97.7 97.7% 128 / 131 100.0% 18 / 18 93.9% 154 / 164 77.3% 34 / 44 85.4% 204 / 239
ezCmdProcessor.hpp 100.0 100.0% 60 / 60 100.0% 5 / 5 87.7% 50 / 57 78.1% 25 / 32 89.3% 67 / 75
ezCnt.hpp 92.9 92.9% 13 / 14 100.0% 6 / 6 80.0% 4 / 5 75.0% 3 / 4 100.0% 12 / 12
ezCron.hpp 95.4 95.4% 267 / 280 100.0% 25 / 25 92.1% 234 / 254 91.7% 132 / 144 82.2% 244 / 297
ezExpr.hpp 94.7 94.7% 408 / 431 97.8% 87 / 89 88.8% 419 / 472 63.6% 14 / 22 70.8% 658 / 929
ezFigFont.hpp 97.0 97.0% 96 / 99 100.0% 9 / 9 92.0% 80 / 87 72.7% 32 / 44 82.8% 106 / 128
ezFile.hpp 77.4 77.4% 24 / 31 100.0% 2 / 2 55.6% 20 / 36 40.0% 4 / 10 45.5% 30 / 66
ezGif.hpp 94.5 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 95.7% 135 / 141 100.0% 6 / 6 72.6% 146 / 201 80.0% 16 / 20 80.0% 168 / 210
ezGraph.hpp 98.4 98.4% 182 / 185 100.0% 51 / 51 75.6% 62 / 82 68.8% 33 / 48 90.9% 229 / 252
ezLog.hpp 76.3 76.3% 58 / 76 88.9% 8 / 9 56.7% 38 / 67 45.8% 11 / 24 70.6% 48 / 68
ezLzw.hpp 96.6 96.6% 57 / 59 100.0% 10 / 10 92.3% 48 / 52 91.7% 11 / 12 83.2% 79 / 95
ezMath.hpp 100.0 100.0% 70 / 70 100.0% 79 / 79 100.0% 24 / 24 100.0% 6 / 6 96.7% 29 / 30
ezNamedPipe.hpp 87.9 87.9% 51 / 58 100.0% 12 / 12 69.7% 23 / 33 68.2% 15 / 22 91.5% 43 / 47
ezStr.hpp 79.4 79.4% 50 / 63 91.7% 11 / 12 59.2% 29 / 49 63.6% 14 / 22 72.1% 31 / 43
ezSvg.hpp 100.0 100.0% 10 / 10 100.0% 2 / 2 100.0% 18 / 18 100.0% 2 / 2 82.9% 29 / 35
ezTime.hpp 100.0 100.0% 2 / 2 100.0% 1 / 1 100.0% 1 / 1 -% 0 / 0 100.0% 4 / 4
ezVdbWriter.hpp 97.6 97.6% 243 / 249 96.8% 60 / 62 81.0% 128 / 158 76.5% 26 / 34 85.0% 216 / 254
ezVec2.hpp 98.6 98.6% 73 / 74 100.0% 161 / 161 80.0% 12 / 15 50.0% 1 / 2 100.0% 49 / 49
ezVec3.hpp 98.3 98.3% 58 / 59 100.0% 143 / 143 71.8% 28 / 39 50.0% 1 / 2 87.2% 41 / 47
ezVec4.hpp 98.3 98.3% 57 / 58 100.0% 128 / 128 75.0% 33 / 44 50.0% 1 / 2 83.9% 47 / 56
ezVoxWriter.hpp 93.8 93.8% 333 / 355 96.1% 49 / 51 88.3% 212 / 240 70.8% 51 / 72 87.5% 393 / 449
ezXml.hpp 92.8 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, "&", "&amp;");
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, "<", "&lt;");
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, "\"", "&quot;");
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, "'", "&apos;");
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, ">", "&gt;");
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, "&lt;", "<");
108 replaceAll(unescaped, "&amp;", "&");
109 replaceAll(unescaped, "&quot;", "\"");
110 replaceAll(unescaped, "&apos;", "'");
111 replaceAll(unescaped, "&gt;", ">");
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