Line data Source code
1 : #ifndef UNIT_UNIT_H
2 : #define UNIT_UNIT_H
3 :
4 :
5 : #include <array>
6 : #include <charconv>
7 : #include <cstdlib>
8 : #include <iostream>
9 : #include <system_error>
10 : #include <unordered_map>
11 : #include <string>
12 : #include <stdexcept>
13 : #include <cmath>
14 : #include <regex>
15 :
16 : #include "Util/Util.H"
17 : //#include "Set/Base.H"
18 : //#include "String.H"
19 :
20 : struct Unit : std::pair<double,std::array<int,7>>
21 : {
22 :
23 : //
24 : // STATIC CONST DEFINITIONS, TRUE EVERYWHERE
25 : //
26 : enum class Type {
27 : Length=0, Time=1, Mass=2, Temperature=3, Current=4, Amount=5, LuminousIntensity=6
28 : };
29 : // Fundamental units
30 : inline static const std::map<std::string, std::pair<double,std::array<int,7>>> base_units =
31 : {
32 : {"1", {1.0, {0,0,0,0,0,0,0}}},
33 : {"m", {1.0, {1,0,0,0,0,0,0}}},
34 : {"s", {1.0, {0,1,0,0,0,0,0}}},
35 : {"kg", {1.0, {0,0,1,0,0,0,0}}},
36 : {"K", {1.0, {0,0,0,1,0,0,0}}},
37 : {"A", {1.0, {0,0,0,0,1,0,0}}},
38 : {"mol",{1.0, {0,0,0,0,0,1,0}}},
39 : {"cd", {1.0, {0,0,0,0,0,0,1}}}
40 : };
41 : //
42 : // Compound unit relationships and nomenclature
43 : // Any desired unit relationship can be added to this list.
44 : // The unit conversion can be specified in any desired format, as long as
45 : // all of the units on the right hand side are resolvable.
46 : //
47 : inline static const std::map<std::string, std::pair<double,std::string>> compound = {
48 : // Lengths
49 : {"km", {1e+3, "m" }},
50 : {"hm", {1e+2, "m" }},
51 : {"dam", {1e+1, "m" }},
52 : {"dm", {1e-1, "m" }},
53 : {"cm", {1e-2, "m" }},
54 : {"mm", {1e-3, "m" }},
55 : {"um", {1e-6, "m" }},
56 : {"nm", {1e-9, "m" }},
57 : {"pm", {1e-12, "m" }},
58 : {"in", {0.0254, "m" }},
59 : {"ft", {0.3048, "m" }},
60 : {"yd", {0.9144, "m" }},
61 : {"mi", {5280.0, "ft" }},
62 : {"furlong", {660.0, "ft" }},
63 : {"au", {1.495978707e11, "m" }}, // astronomical unit
64 : {"ly", {9.4607304725808e15, "m"}}, // lightyear
65 : {"pc", {3.08567758149137e16, "m"}}, // parsec
66 :
67 : // Angles
68 : {"rad", {1.0, "1"}},
69 : {"deg", {0.01745329251, "rad" }},
70 :
71 : // Times
72 : {"ms", {1e-3, "s" }},
73 : {"us", {1e-6, "s" }},
74 : {"ns", {1e-9, "s" }},
75 : {"ps", {1e-12, "s" }},
76 : {"min", {60.0, "s" }},
77 : {"hr", {60.0, "min" }},
78 : {"day", {24.0, "hr" }},
79 : {"week", {7.0, "day" }},
80 : {"fortnight", {14.0, "day" }},
81 : {"year", {365.25, "day" }},
82 : {"decade", {10.0, "year" }},
83 :
84 : // Mass
85 : {"g", {1e-3, "kg" }},
86 : {"mg", {1e-6, "kg" }},
87 : {"ug", {1e-9, "kg" }},
88 : {"tonne", {1000.0, "kg" }},
89 : {"lb", {0.45359237, "kg" }},
90 : {"oz", {0.0283495, "kg" }},
91 : {"slug", {14.5939, "kg" }},
92 :
93 : // Speed
94 : {"mph", {1.0, "mi/hr" }},
95 : {"kph", {1.0, "km/hr" }},
96 : {"mps", {1.0, "m/s" }},
97 : {"fps", {1.0, "ft/s" }},
98 : {"knot", {1852.0 / 3600.0, "m/s"}},
99 :
100 : // Area
101 : {"ha", {1e4, "m^2" }},
102 : {"acre", {4046.85642, "m^2" }},
103 : {"sqft", {1.0, "ft^2" }},
104 : {"sqin", {1.0, "in^2" }},
105 : {"sqkm", {1.0, "km^2" }},
106 : {"sqmi", {1.0, "mi^2" }},
107 :
108 : // Volume
109 : {"L", {1e-3, "m^3" }},
110 : {"mL", {1e-6, "m^3" }},
111 : {"cc", {1e-6, "m^3" }},
112 : {"gal", {3.78541e-3, "m^3" }},
113 : {"qt", {0.946353e-3, "m^3" }},
114 : {"pt", {0.473176e-3, "m^3" }},
115 : {"cup", {0.24e-3, "m^3" }},
116 : {"floz", {29.5735e-6, "m^3" }},
117 : {"tbsp", {14.7868e-6, "m^3" }},
118 : {"tsp", {4.92892e-6, "m^3" }},
119 :
120 : // Force
121 : {"N", {1.0, "kg*m/s^2" }},
122 : {"kN", {1e3, "N" }},
123 : {"lbf", {4.44822162, "N" }},
124 : {"dyn", {1e-5, "N" }},
125 :
126 : // Energy
127 : {"J", {1.0, "N*m" }},
128 : {"mJ", {1e-3, "J" }},
129 : {"kJ", {1e3, "J" }},
130 : {"MJ", {1e6, "J" }},
131 : {"eV", {1.602176634e-19, "J"}},
132 : {"cal", {4.184, "J" }},
133 : {"kcal", {4184.0, "J" }},
134 : {"BTU", {1055.06, "J" }},
135 : {"ft*lbf", {1.35582, "J" }},
136 :
137 : // Power
138 : {"W", {1.0, "J/s" }},
139 : {"mW", {1e-3, "W" }},
140 : {"kW", {1e3, "W" }},
141 : {"MW", {1e6, "W" }},
142 : {"hp", {745.7, "W" }},
143 :
144 : // Pressure
145 : {"Pa", {1.0, "N/m^2" }},
146 : {"kPa", {1e3, "Pa" }},
147 : {"MPa", {1e6, "Pa" }},
148 : {"GPa", {1e9, "Pa" }},
149 : {"bar", {1e5, "Pa" }},
150 : {"atm", {101325.0,"Pa" }},
151 : {"psi", {6894.76, "Pa" }},
152 : {"mmHg", {133.322, "Pa" }},
153 : {"torr", {133.322, "Pa" }},
154 :
155 : // Temperature differences (not absolute temperatures)
156 : {"K", {1.0, "K" }},
157 : {"degR", {5.0/9.0, "K" }},
158 :
159 : // Charge
160 : {"C", {1.0, "A*s" }},
161 : {"mAh", {3.6, "C" }},
162 :
163 : // Voltage
164 : {"V", {1.0, "J/C" }},
165 :
166 : // Capacitance
167 : {"F", {1.0, "C/V" }},
168 :
169 : // Resistance
170 : {"ohm", {1.0, "V/A" }},
171 : {"kOhm", {1e3, "ohm" }},
172 : {"MOhm", {1e6, "ohm" }},
173 :
174 : // Conductance
175 : {"S", {1.0, "1/ohm" }},
176 :
177 : // Magnetic
178 : {"T", {1.0, "kg/(A*s^2)"}},
179 : {"G", {1e-4, "T" }}, // gauss
180 :
181 : // Frequency
182 : {"Hz", {1.0, "1/s" }},
183 : {"kHz", {1e3, "Hz" }},
184 : {"MHz", {1e6, "Hz" }},
185 : {"GHz", {1e9, "Hz" }},
186 :
187 : // Moles
188 : {"kmol", {1e3, "mol" }}
189 : };
190 :
191 :
192 : //
193 : // These static factory functions return unit types.
194 : // They are used to check unit compliance, mainly at the parsing stage.
195 : //
196 : // Primary
197 3125 : static Unit Less() { return Unit{1.0, {0,0,0,0,0,0,0}}; } // 1
198 323 : static Unit Length() { return Unit{1.0, {1,0,0,0,0,0,0}}; } // m
199 464 : static Unit Time() { return Unit{1.0, {0,1,0,0,0,0,0}}; } // s
200 101 : static Unit Mass() { return Unit{1.0, {0,0,1,0,0,0,0}}; } // kg
201 77 : static Unit Temperature() { return Unit{1.0, {0,0,0,1,0,0,0}}; } // K
202 42 : static Unit Current() { return Unit{1.0, {0,0,0,0,1,0,0}}; } // A
203 42 : static Unit Amount() { return Unit{1.0, {0,0,0,0,0,1,0}}; } // mol
204 42 : static Unit LuminousIntensity() { return Unit{1.0, {0,0,0,0,0,0,1}}; } // cd
205 :
206 : static Unit Angle() {return Unit::Less();}
207 :
208 : // Geometry and kinematics
209 26 : static Unit Area() { return Length()*Length(); }
210 9 : static Unit Volume() { return Length()*Length()*Length(); }
211 52 : static Unit Velocity() { return Length() / Time();}
212 44 : static Unit Acceleration(){ return Velocity() / Time(); }
213 : // Mechanics
214 44 : static Unit Force() { return Mass() * Acceleration(); } // kg·m/s² = N
215 : static Unit Momentum() { return Mass() * Velocity(); }
216 : static Unit Impulse() { return Force() * Time(); }
217 15 : static Unit Pressure() { return Force() / Area(); } // N/m² = Pa
218 29 : static Unit Energy() { return Force() * Length(); } // N·m = J
219 8 : static Unit Power() { return Energy() / Time(); } // J/s = W
220 9 : static Unit Density() { return Mass() / Volume(); }
221 : static Unit SpecificWeight() { return Force() / Volume(); }
222 : static Unit Work() { return Energy(); }
223 : // Thermodynamics
224 6 : static Unit SpecificHeatCapacity() {return Energy() / Mass() / Temperature() ;}
225 : static Unit MolarHeatCapacity() {return Energy() / Amount() / Temperature() ;}
226 6 : static Unit ThermalConductivity() {return Power()/Length()/Temperature();}
227 4 : static Unit ThermalDiffusivity() {return ThermalConductivity() / Density() / SpecificHeatCapacity();}
228 : static Unit HeatFlux() { return Power() / Area(); }
229 : static Unit HeatTransferCoefficient() { return HeatFlux() / Temperature(); }
230 : // Electromagnetism
231 :
232 : static Unit Charge() { return Current() * Time(); } // A·s = C
233 : static Unit Voltage() { return Power() / Current(); } // W/A = V
234 : static Unit Resistance() { return Voltage() / Current(); } // V/A = Ω
235 : static Unit Capacitance() { return Charge() / Voltage(); } // C/V = F
236 : static Unit Conductance() { return Less() / Resistance(); } // S = 1/Ω
237 : static Unit MagneticFlux(){ return Voltage() * Time(); } // V·s = Wb
238 : static Unit MagneticField(){ return MagneticFlux() / Area(); } // Wb/m² = T
239 : static Unit Inductance() { return MagneticFlux() / Current(); } // Wb/A = H
240 : // Chemistry
241 : static Unit MolarMass() { return Mass() / Amount(); } // kg/mol
242 : static Unit Concentration(){ return Amount() / Volume(); } // mol/m³
243 : static Unit MolarEnergy() { return Energy() / Amount(); } // J/mol
244 : // Optics and radiation
245 : static Unit LuminousFlux() { return LuminousIntensity(); } // for scalar usage (lm)
246 : static Unit Illuminance() { return LuminousFlux() / Area(); } // lux = lm/m²
247 :
248 :
249 : //
250 : // This is where SYSTEM NORMALIZATION is stored.
251 : // Should usually be set once (at the beginning of the simulation) and then
252 : // left constant throughout the simulation.
253 : // All normalizations are in terms of standard SI units: m,s,kg,K,A,mol,cd.
254 : //
255 : inline static std::array<std::pair<std::string,double>, 7> normalization = {
256 : std::pair{"m", 1.0},
257 : std::pair{"s", 1.0},
258 : std::pair{"kg", 1.0},
259 : std::pair{"K", 1.0},
260 : std::pair{"A", 1.0},
261 : std::pair{"mol",1.0},
262 : std::pair{"cd", 1.0}
263 : };
264 :
265 : using std::pair<double, std::array<int,7>>::pair;
266 1745 : Unit(const std::pair<double, std::array<int, 7>>& p) : std::pair<double, std::array<int, 7>>(p) {}
267 : static std::map<std::string, int> ParseUnitString(const std::string& input);
268 :
269 :
270 524 : static Unit Parse(double val, std::string unitstring, bool verbose = false)
271 : {
272 524 : Unit ret = StringParse(unitstring, verbose);
273 524 : ret.first *= val;
274 524 : return ret;
275 : }
276 1133 : static Unit Parse(std::string unit, bool verbose = false)
277 : {
278 1133 : if (unit.size() == 0) return Unit::Less();
279 1107 : std::vector<std::string> split;
280 1107 : std::stringstream ss(unit);
281 1107 : std::string item;
282 2738 : while (std::getline(ss, item, '_')) {
283 1631 : split.push_back(item);
284 : }
285 1107 : if (split.size() == 2)
286 : {
287 524 : return Parse(std::stod(split[0]),split[1], verbose);
288 : }
289 583 : else if (split.size() == 1)
290 : {
291 : // Attempt to parse the string as if it's a unitless number
292 583 : double value = NAN;
293 :
294 : // auto first = unit.data();
295 : // auto last = unit.data() + unit.size();
296 : // auto result = std::from_chars(first, last, value); // apparently this fails on mac
297 :
298 583 : char *end = nullptr;
299 583 : value = std::strtod(unit.c_str(), &end);
300 :
301 : // If it is a untless number, then return a unitless result
302 : //if (result.ec == std::errc() && result.ptr == last) // fails on mac
303 583 : if (end != unit.data() && *end == '\0')
304 : {
305 581 : Unit ret = Unit::Less();
306 581 : ret.first = value;
307 581 : return ret;
308 : }
309 : // Otherwise, it must be a pure unit, so return that.
310 : else
311 : {
312 2 : return StringParse(unit);
313 : }
314 : }
315 : else
316 : {
317 0 : throw std::runtime_error("Invalid unit string "+unit);
318 : }
319 1107 : }
320 :
321 :
322 1420 : static Unit StringParse(std::string unitstring, bool verbose = false)
323 : {
324 1420 : Unit type = Unit::Less();
325 :
326 : // Get the map of base tokens with signed exponents from ParseUnitString
327 1420 : std::map<std::string,int> parsed_units = ParseUnitString(unitstring);
328 1420 : if (verbose)
329 : {
330 0 : for (auto parsed_unit : parsed_units)
331 : {
332 0 : std::cout << parsed_unit.first << " " << parsed_unit.second << std::endl;
333 0 : }
334 : }
335 :
336 3765 : for (auto &p : parsed_units)
337 : {
338 2345 : const std::string &token = p.first;
339 2345 : int exp = p.second;
340 :
341 2345 : if (Unit::base_units.find(token) != base_units.end())
342 : {
343 : // Base unit: apply exponent
344 1745 : Unit t = Unit(Unit::base_units.at(token)) ^ exp;
345 1745 : type = type * t;
346 : }
347 600 : else if (compound.find(token) != compound.end())
348 : {
349 : // Compound unit: expand recursively
350 600 : auto pair = compound.at(token);
351 600 : double factor = pair.first;
352 600 : const std::string &subunit_str = pair.second;
353 :
354 600 : Unit t = StringParse(subunit_str); // recursive expansion
355 600 : t = t ^ exp; // apply exponent to both factor and dimension
356 600 : t.first *= std::pow(factor, exp); // scale numeric factor correctly
357 :
358 600 : type = type * t;
359 600 : }
360 : else
361 : {
362 0 : throw std::runtime_error("Unknown unit token: " + token);
363 : }
364 : }
365 :
366 2840 : return type;
367 1420 : }
368 :
369 42 : static void setLengthUnit(std::string unit)
370 : {
371 42 : Unit parsed = StringParse(unit);
372 42 : if (parsed.second != Length().second) throw std::runtime_error("Not a unit of length: " + unit);
373 42 : normalization[int(Type::Length)].first = unit;
374 42 : normalization[int(Type::Length)].second = 1.0 / parsed.first;
375 42 : }
376 :
377 42 : static void setTimeUnit(std::string unit)
378 : {
379 42 : Unit parsed = StringParse(unit);
380 42 : if (parsed.second != Time().second) throw std::runtime_error("Not a unit of time: " + unit);
381 42 : normalization[int(Type::Time)].first = unit;
382 42 : normalization[int(Type::Time)].second = 1.0 / parsed.first;
383 42 : }
384 :
385 42 : static void setMassUnit(std::string unit)
386 : {
387 42 : Unit parsed = StringParse(unit);
388 42 : if (parsed.second != Mass().second) throw std::runtime_error("Not a unit of mass: " + unit);
389 42 : normalization[int(Type::Mass)].first = unit;
390 42 : normalization[int(Type::Mass)].second = 1.0 / parsed.first;
391 42 : }
392 :
393 42 : static void setTemperatureUnit(std::string unit)
394 : {
395 42 : Unit parsed = StringParse(unit);
396 42 : if (parsed.second != Temperature().second) throw std::runtime_error("Not a unit of temperature: " + unit);
397 42 : normalization[int(Type::Temperature)].first = unit;
398 42 : normalization[int(Type::Temperature)].second = 1.0 / parsed.first;
399 42 : }
400 :
401 42 : static void setCurrentUnit(std::string unit)
402 : {
403 42 : Unit parsed = StringParse(unit);
404 42 : if (parsed.second != Current().second) throw std::runtime_error("Not a unit of current: " + unit);
405 42 : normalization[int(Type::Current)].first = unit;
406 42 : normalization[int(Type::Current)].second = 1.0 / parsed.first;
407 42 : }
408 :
409 42 : static void setAmountUnit(std::string unit)
410 : {
411 42 : Unit parsed = StringParse(unit);
412 42 : if (parsed.second != Amount().second) throw std::runtime_error("Not a unit of amount: " + unit);
413 42 : normalization[int(Type::Amount)].first = unit;
414 42 : normalization[int(Type::Amount)].second = 1.0 / parsed.first;
415 42 : }
416 :
417 42 : static void setLuminousIntensityUnit(std::string unit)
418 : {
419 42 : Unit parsed = StringParse(unit);
420 42 : if (parsed.second != LuminousIntensity().second) throw std::runtime_error("Not a unit of luminous intensity: " + unit);
421 42 : normalization[int(Type::LuminousIntensity)].first = unit;
422 42 : normalization[int(Type::LuminousIntensity)].second = 1.0 / parsed.first;
423 42 : }
424 :
425 1368 : bool isType(const Unit &test) const
426 : {
427 1368 : return this->second == test.second;
428 : }
429 :
430 2462 : Unit operator * (const Unit &rhs)
431 : {
432 2462 : Unit ret;
433 2462 : ret.first = this->first * rhs.first;
434 22158 : for (unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i] + rhs.second[i];
435 2462 : return ret;
436 : }
437 0 : friend Unit operator*(double lhs, const Unit& rhs) {
438 0 : Unit ret;
439 0 : ret.first = lhs * rhs.first;
440 0 : ret.second = rhs.second;
441 0 : return ret;
442 : }
443 : friend Unit operator*(const Unit& lhs, double rhs) {
444 : Unit ret;
445 : ret.first = rhs * lhs.first;
446 : ret.second = lhs.second;
447 : return ret;
448 : }
449 186 : Unit operator / (const Unit &rhs)
450 : {
451 186 : Unit ret;
452 186 : ret.first = this->first / rhs.first;
453 1674 : for (unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i] - rhs.second[i];
454 186 : return ret;
455 : }
456 3 : friend Unit operator / (double lhs, const Unit& rhs) {
457 3 : Unit ret = Unit::Less() / rhs;
458 3 : ret.first = lhs * rhs.first;
459 3 : return ret;
460 : }
461 : friend Unit operator / (const Unit& lhs, double rhs) {
462 : Unit ret;
463 : ret.first = lhs.first / rhs;
464 : ret.second = lhs.second;
465 : return ret;
466 : }
467 : Unit operator + (const Unit &rhs)
468 : {
469 : Util::Assert(INFO, TEST(this->second == rhs.second), "Error adding values with unequal units");
470 : Unit ret;
471 : ret.first = this->first + rhs.first;
472 : for (unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i];
473 : return ret;
474 : }
475 : Unit operator - (const Unit &rhs)
476 : {
477 : Util::Assert(INFO, TEST(this->second == rhs.second), "Error subtracting values with unequal units");
478 : Unit ret;
479 : ret.first = this->first - rhs.first;
480 : for (unsigned int i = 0; i < this->second.size(); i++) ret.second[i] = (this->second)[i];
481 : return ret;
482 : }
483 2345 : Unit operator ^ (const int &rhs)
484 : {
485 2345 : Unit ret;
486 2345 : ret.first = std::pow(this->first,rhs);
487 37520 : for (unsigned int i = 0; i < this->second.size(); i++)
488 : {
489 16415 : ret.second[i] = (this->second)[i]*rhs;
490 : }
491 2345 : return ret;
492 : }
493 :
494 0 : friend std::ostream& operator<<(std::ostream &out, const Unit &a)
495 : {
496 0 : out << a.normalized_value() << "_";
497 0 : out << a.normalized_unitstring();
498 0 : return out;
499 : }
500 :
501 1135 : double normalized_value() const
502 : {
503 1135 : double fac = 1.0;
504 18160 : for (unsigned int i = 0 ; i < this->second.size(); i++)
505 7945 : fac *= std::pow(normalization[i].second, this->second[i]);
506 :
507 1135 : return this->first * fac;
508 : }
509 :
510 0 : std::string normalized_unitstring() const
511 : {
512 : // little utility to join strings with delimiter
513 0 : auto join = [] (std::vector<std::string>vec,std::string sep){
514 0 : std::ostringstream oss;
515 0 : for (size_t i = 0; i < vec.size(); ++i) {
516 0 : oss << vec[i];
517 0 : if (i < vec.size() - 1) {
518 0 : oss << sep;
519 : }
520 : }
521 0 : return oss.str();
522 0 : };
523 :
524 0 : std::vector<std::string> num, den;
525 0 : for (unsigned int i = 0 ; i < this->second.size(); i++)
526 : {
527 0 : if (this->second[i] > 1)
528 0 : num.push_back(normalization[i].first + "^" + std::to_string(this->second[i]));
529 0 : else if (this->second[i] == 1)
530 0 : num.push_back(normalization[i].first);
531 0 : else if (this->second[i] == -1)
532 0 : den.push_back(normalization[i].first);
533 0 : else if (this->second[i] < -1)
534 0 : den.push_back(normalization[i].first + "^" + std::to_string(std::abs(this->second[i])));
535 : }
536 :
537 0 : std::string ret;
538 0 : if (num.size()) ret = join(num,"*");
539 0 : else ret = "1";
540 0 : if (den.size()) ret += "/" + join(den,"/");
541 :
542 0 : return ret;
543 0 : }
544 : };
545 :
546 :
547 : inline std::map<std::string, int>
548 1420 : Unit::ParseUnitString(const std::string& input) {
549 1420 : std::map<std::string, int> result;
550 : enum class Op { Mul = 1, Div = -1 };
551 1420 : Op currentOp = Op::Mul;
552 1420 : std::string token;
553 1420 : size_t i = 0;
554 2345 : auto parse_unit = [&](const std::string& t, Op op) {
555 2345 : if (t.empty()) return;
556 :
557 2345 : size_t caret = t.find('^');
558 2345 : std::string base = t;
559 2345 : int exp = 1;
560 :
561 2345 : if (caret != std::string::npos) {
562 333 : base = t.substr(0, caret);
563 333 : std::string exp_str = t.substr(caret + 1);
564 : try {
565 333 : exp = std::stoi(exp_str);
566 0 : } catch (...) {
567 0 : throw std::runtime_error("Invalid exponent: " + exp_str);
568 0 : }
569 333 : }
570 2345 : int signed_exp = (op == Op::Mul ? +1 : -1) * exp;
571 2345 : result[base] += signed_exp;
572 2345 : };
573 :
574 6203 : while (i < input.size()) {
575 4783 : char c = input[i];
576 :
577 4783 : if (c == '*')
578 : {
579 357 : parse_unit(token, currentOp);
580 357 : token.clear();
581 357 : currentOp = Op::Mul;
582 357 : ++i;
583 : }
584 4426 : else if (c == '/')
585 : {
586 568 : parse_unit(token, currentOp);
587 568 : token.clear();
588 568 : currentOp = Op::Div;
589 568 : ++i;
590 : }
591 : else
592 : {
593 3858 : token += c;
594 3858 : ++i;
595 : }
596 : }
597 :
598 : // Parse final token
599 1420 : parse_unit(token, currentOp);
600 :
601 2840 : return result;
602 1420 : }
603 :
604 :
605 :
606 :
607 :
608 :
609 :
610 :
611 :
612 :
613 : #endif
|