-
Notifications
You must be signed in to change notification settings - Fork 1
/
NumberWithUnits.cpp
326 lines (302 loc) · 11.6 KB
/
NumberWithUnits.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#include "NumberWithUnits.hpp"
using namespace::std;
namespace ariel {
/**
* @brief Construct a new Number With Units:: Number With Units object
*
* @param amount the amount of the created unit
* @param unit_type the unit type, must be from the current unit table
*/
NumberWithUnits::NumberWithUnits(double amount, const string &unit_type) {
if (units_map.count(unit_type) > 0) {
_unit.first = amount;
_unit.second = unit_type;
}
else {
throw("This unit does not exist!");
}
}
/**
* @brief Reads the units and arranges them in the current units table
* For each and every unit we crate a dedicated map that contains all
* of its convertable units and their conversion value
*
* @param file_name file stream of the txt file to be readed from
*/
void NumberWithUnits::read_units(ifstream &file_name) {
string unit1, unit2;
double amount = 0;
while (!file_name.fail() && !file_name.eof() ) {
file_name >> unit1 >> unit1;
file_name >> unit2;
file_name >> amount;
file_name >> unit2;
units_map[unit1][unit2] = amount;
units_map[unit2][unit1] = 1/amount;
for (auto const &unit : units_map[unit1]) {
units_map[unit.first][unit2] = amount / unit.second;
units_map[unit2][unit.first] = unit.second / amount;
}
for (auto const &unit : units_map[unit2]) {
units_map[unit.first][unit1] = (1/amount) / unit.second;
units_map[unit1][unit.first] = unit.second / (1/amount);
}
}
}
/**
* @brief check the compability of conversion between two different units
* by checking if each and every one of them is present in each other value map
*
* @param unit1 first unit to check
* @param unit2 second unit to check
* @return true if they math
* @return false otherwise
*/
bool NumberWithUnits::check_units_compability(const string unit1, const string unit2) const {
if (units_map[unit1].count(unit2) > 0 && units_map[unit2].count(unit1) > 0) {
return true;
}
return false;
}
/**
* @brief unary - operator, multiplies the current amount with a negative value
*
* @return NumberWithUnits a new object with it's value multiplied by (-1)
*/
NumberWithUnits NumberWithUnits::operator- () const {
NumberWithUnits result(_unit.first * (-1), _unit.second);
return result;
}
/**
* @brief postfix decrease by 1
*
* @return NumberWithUnits& reference to the current object after the chagne
*/
NumberWithUnits & NumberWithUnits::operator-- () {
_unit.first = _unit.first -1;
return *this;
}
/**
* @brief postfix increase by 1
*
* @return NumberWithUnits& reference to the current object after the chagne
*/
NumberWithUnits & NumberWithUnits::operator++ () {
_unit.first = _unit.first +1;
return *this;
}
/**
* @brief prefix decrease by one
*
* @return NumberWithUnits a new object representing the current object before the change
*/
NumberWithUnits NumberWithUnits::operator-- (int) {
NumberWithUnits result(_unit.first, _unit.second);
_unit.first = _unit.first -1;
return result;
}
/**
* @brief prefix increase by one
*
* @return NumberWithUnits a new object representing the current object before the change
*/
NumberWithUnits NumberWithUnits::operator++ (int) {
NumberWithUnits result(_unit.first, _unit.second);
_unit.first = _unit.first +1;
return result;
}
/**
* @brief binary decrease operator
*
* @param other_num the rval of the equation
* @return NumberWithUnits the result if the units match
*/
NumberWithUnits NumberWithUnits::operator- (const NumberWithUnits &other_num) const {
if (check_units_compability(_unit.second, other_num._unit.second)) {
return NumberWithUnits(_unit.first - (other_num._unit.first * units_map[other_num._unit.second][_unit.second]), _unit.second);
}
throw("Units does not match");
}
/**
* @brief unary - operator, multiplies the current amount with a positive 1 value
*
* @return NumberWithUnits reference to the same object with no change
*/
NumberWithUnits NumberWithUnits::operator+ () const {
return *this;
}
/**
* @brief binary increase operator
*
* @param other_num the rval of the equation
* @return NumberWithUnits the result if the units match
*/
NumberWithUnits NumberWithUnits::operator+ (const NumberWithUnits &other_num) const {
if (check_units_compability(_unit.second, other_num._unit.second)) {
return NumberWithUnits(_unit.first + (other_num._unit.first * units_map[other_num._unit.second][_unit.second]), _unit.second);
}
throw("Units does not match");
}
/**
* @brief comperator operator checks if the left object is bigger then the right object
* will throw an exception if the units does not match
*
* @param other_num the right object to compare
* @return true if the left is bigger
* @return false otherwise
*/
bool NumberWithUnits::operator> (const NumberWithUnits &other_num) const {
if (check_units_compability(_unit.second, other_num._unit.second)) {
return (units_map[_unit.second][other_num._unit.second] * _unit.first > other_num._unit.first
|| (units_map[_unit.second][other_num._unit.second] * _unit.first - other_num._unit.first) > epsilon);
}
throw("Units does not match");
}
/**
* @brief comperator operator checks if the left object is smaller then the right object
* will throw an exception if the units does not match
*
* @param other_num the right object to compare
* @return true if the right is bigger
* @return false otherwise
*/
bool NumberWithUnits::operator< (const NumberWithUnits &other_num) const {
if (check_units_compability(_unit.second, other_num._unit.second)) {
return (this->_unit.first < other_num._unit.first * units_map[other_num._unit.second][_unit.second]);
}
throw("Units does not match");
}
/**
* @brief comperator operator checks if the left object is smaller or equal to the right object
* will throw an exception if the units does not match
*
* @param other_num the right object to compare
* @return true if the right is bigger or equal
* @return false otherwise
*/
bool NumberWithUnits::operator<= (const NumberWithUnits &other_num) const {
return (*this < other_num || *this == other_num);
}
/**
* @brief comperator operator checks if the left object is bigger or equal to the right object
* will throw an exception if the units does not match
*
* @param other_num the right object to compare
* @return true if the right is smaller or equal
* @return false otherwise
*/
bool NumberWithUnits::operator>= (const NumberWithUnits &other_num) const {
if (check_units_compability(_unit.second, other_num._unit.second)) {
return (this->_unit.first >= other_num._unit.first * units_map[other_num._unit.second][_unit.second]);
}
throw("Units does not match");
}
/**
* @brief inequality comperator will throw an exception if the units does not match
*
* @param other_num the right object to compare
* @return true if both objects are not equal
* @return false otherwise
*/
bool NumberWithUnits::operator!= (const NumberWithUnits &other_num) const {
return !(*this == other_num);
}
/**
* @brief the equality operator, checks if two objects are equal by amount and value
* for precision purposes compare them by using a small epsilon
*
* @param other_num the other number to check
* @return true if they are equal
* @return false otherwise (throws an exception if they don't match)
*/
bool NumberWithUnits::operator== (const NumberWithUnits &other_num) const {
if (check_units_compability(_unit.second, other_num._unit.second)) {
return (abs(_unit.first - other_num._unit.first * units_map[other_num._unit.second][_unit.second]) <= epsilon);
}
throw("Wrong Unit");
}
/**
* @brief binary increase operator
*
* @param num the number to increase by
* @return NumberWithUnits& reference to the number after the change
*/
NumberWithUnits& NumberWithUnits::operator+= (const NumberWithUnits &num) {
if (check_units_compability(_unit.second, num._unit.second)) {
_unit.first += (num._unit.first * units_map[num._unit.second][_unit.second]);
return *this;
}
throw("Units does not match");
}
/**
* @brief binary decrease operator
*
* @param num the number to decrease by
* @return NumberWithUnits& reference to the number after the change
*/
NumberWithUnits& NumberWithUnits::operator-= (const NumberWithUnits &num) {
if (check_units_compability(_unit.second, num._unit.second)) {
_unit.first -= (num._unit.first * units_map[num._unit.second][_unit.second]);
return *this;
}
throw("Units does not match");
}
/**
* @brief multiplication operator for multiplying an object with a number
*
* @param factor the real number factor to multiply by
* @return NumberWithUnits the result
*/
NumberWithUnits NumberWithUnits::operator* (double factor) const {
return NumberWithUnits(_unit.first * factor, this->_unit.second);
}
/**
* @brief multiplication operator for multiplying a number with an object
*
* @param factor the real number factor to multiply by
* @param other_num the number object to multiply
* @return NumberWithUnits
*/
NumberWithUnits operator* (double factor, const NumberWithUnits &other_num) {
return other_num * factor;
}
/**
* @brief output stream operator that defines the outputstream form of the objects
* print "amount[unit name]"
*
* @param stream outpust stream
* @param num number to print
* @return ostream& outpust stream with the result
*/
ostream& operator<< (ostream& stream, const NumberWithUnits &num) {
stream << num._unit.first << "[" << num._unit.second << "]";
return stream;
}
/**
* @brief input stream the can generate an object (or several objects)
* from a string stream converts the "amount[unit name]" form back to an object form
*
* @param stream input stream
* @param num number to manipulate with the new unit
* @return istream& input stream with result only if the unit is in the table
*/
istream& operator>> (istream& stream, NumberWithUnits &num) {
double in_num = 0;
string result;
char tmp_char = ' ';
stream >> in_num;
stream >> tmp_char ;
while (tmp_char != ']') {
if (tmp_char != '[') {
result.push_back(tmp_char);
}
stream >> tmp_char;
}
if (units_map.count(result) > 0) {
num._unit.first = in_num;
num._unit.second = result;
return stream;
}
throw("Wrong Unit");
}
}