HRCore V1.1.0
A High Resolution Calculation Library
Loading...
Searching...
No Matches
Utils.hpp
Go to the documentation of this file.
1
9#ifndef __HRCORE_UTILS_HPP__
10#define __HRCORE_UTILS_HPP__
11
12#include "../HRCore.h"
13
14namespace HRCore {
15
19namespace Internal {
22 {
23 if (!i)
24 return false;
25 auto t = i->next(r);
26 if (t) {
27 r = t;
28 return true;
29 } else {
30 bool ret = i->extend(i->length() << 1);
31 r = i->next(r);
32 return ret;
33 }
34 }
35}
36
42namespace Value {
56 std::ostream& operator<<(std::ostream& os, Integer& rhs)
57 {
58 if (os.flags() & std::ios_base::hex) { // Hex
59 auto t = rhs._idata->end();
60 os << (rhs._isPostive ? "" : "-") << (os.flags() & std::ios_base::showbase ? "0x" : "");
61 while (t) {
62 auto m = rhs._idata->prev(t);
63 os << *t.data << (m ? "," : "");
64 t = m;
65 }
66 } else { // Dec
67 Integer div = rhs.make() = 1000;
68 Integer src = rhs;
69 auto ret = rhs._idata->newObject();
70 ret->extend(rhs._idata->length() * 3);
71 os << (rhs._isPostive ? "" : "-");
72 auto r = ret->begin();
73 while (Integer::_absGreater(src, div)) {
74 auto tmp = src.divideBy(div);
75 *r.data = *(tmp.getRemainder()._idata->begin().data);
77 src = tmp.getQuotient();
78 }
79 *r.data = *src._idata->begin().data;
80 for (bool flag = false; r; flag = true) {
81 auto t = ret->prev(r);
82 if (flag) { // Not highest bit; add 0 to get 3 digits
83 if (*r.data < 10) {
84 os << "00";
85 } else if (*r.data < 100) {
86 os << "0";
87 }
88 }
89 if (*r.data == 1000) {
90#if HRCORE_ENABLE_IO_DELIMETER
91 os << "1,000";
92#else
93 os << "1000";
94#endif
95 } else {
96 os << *r.data;
97 }
98#if HRCORE_ENABLE_IO_DELIMETER
99 os << (t ? "," : "");
100#endif
101 r = t;
102 }
103 }
104
105 return os;
106 }
107
119 std::istream& operator>>(std::istream& is, Integer& rhs)
120 {
121 int c = EOF;
122 while ((c = is.peek()) == ' ' || c == '\n' || c == '\r') // Remove prefix invalid characters
123 is.ignore();
124 if (c == EOF) {
125 rhs = 0;
126 return is;
127 }
128 if (is.flags() & std::ios_base::hex) { // Hex
129 ival_t data = 0;
130 auto ret = rhs._idata->newObject();
131 auto r = ret->begin();
132 while ((c = is.peek()) != EOF) {
133 if (c == ',' || c == ' ' || c == '\n') { // Item delimeter
134 is.ignore();
135 *r.data = data;
137 if (c == ',')
138 continue;
139 r = ret->prev(r);
140 break;
141 }
142 is >> data;
143 }
144 if (c == EOF) // Write back remain data
145 *r.data = data;
146 if (ret->length() > rhs._idata->length()) {
147 rhs._idata->extend(ret->length());
148 } else {
149 rhs._idata->shrink(ret->length());
150 }
151 for (auto x = rhs._idata->begin(); x && r; x = rhs._idata->next(x), r = ret->prev(r)) // Reverse copy
152 *x.data = *r.data;
153 ret->delObject(ret); // Don't forget to release memory
154 rhs._simplify();
155 } else { // Decimal
156 Integer tim = rhs.make() = 10;
157 rhs = 0; // Clear original value
158 bool positive = (c != '-');
159 if (c == '-' || c == '+')
160 is.ignore();
161 while ((c = is.get()) != EOF) {
162 HRCORE_DBG(std::cout << c - '0' << std::endl;)
163 if (c >= '0' && c <= '9') {
164 Integer tmp = rhs.make() = c - '0';
165 rhs = rhs * tim + tmp;
166 } else if (c == ',') {
167 continue;
168 } else {
169 is.putback(c);
170 break;
171 }
172 }
173 rhs.positive(positive);
174 }
175 return is;
176 }
177
178#if HRCORE_ENABLE_FP
179
185 std::istream& operator>>(std::istream& is, Float& rhs)
186 {
187 if (is.flags() & std::ios_base::hex)
188 return is;
189 operator>>(is, (Integer&)rhs);
190 bool flag = rhs._isPostive;
191 rhs._isPostive = true;
192 int c = is.peek();
193 Integer div = rhs.make() = 1;
194 Float dim = rhs.make();
195 int dtmp = -HRCORE_FP_BITS_BASE;
196 size_t tpos = 0;
197 Float tim = rhs.make() = 10;
198 if (c == '.') {
199 is.ignore();
200 while ((c = is.get()) != EOF) {
201 if (c >= '0' && c <= '9') {
202 Integer tmp = rhs.make() = c - '0';
203 dim = dim * tim + tmp;
204 div = div * tim;
206 ++tpos;
207 } else if (c == ',') {
208 continue;
209 } else {
210 is.putback(c);
211 break;
212 }
213 }
214 }
215 if (tpos < rhs._precision) {
216 dim = dim * tim;
217 div = div * tim;
218 ++tpos;
220 }
221 rhs = rhs + Float((dim << -dtmp) / div, dtmp, tpos);
222 rhs._isPostive = flag;
223 HRCORE_DBGI(std::cout << "[operator>> @ Float] " << rhs._fpos << std::endl;)
224 return is;
225 }
226
232 std::ostream& operator<<(std::ostream& os, Float& rhs)
233 {
234 if (os.flags() & std::ios_base::hex)
235 return os;
236 auto it = rhs.getInteger();
237 if (rhs._fpos < 0) {
238 // os << '.';
239 auto dtmp = rhs - Float(it);
240 Float tim = rhs.make() = 10;
241 // Integer vd = rhs.make() = 9;
242 auto ret = tim._idata->newObject();
243 auto r = ret->begin();
244 size_t n = 0;
245 Float tmp = dtmp * tim;
246 while (!Integer::_isZero(tmp)) {
247 auto x = tmp.getInteger();
248 *r.data = *(((Float*)&x)->_idata->begin().data);
250 ++n;
251 HRCORE_DBG(operator<<(os, x);)
252 tmp = (tmp - x) * tim; // Remove integer part and get next digit
253 }
254 HRCORE_DBG(os << std::endl;)
255 if (n == 0) { // No digit
256 operator<<(os, it);
257 if (os.flags() & std::ios_base::showpoint)
258 os << ".0";
259 return os;
260 }
261 size_t i = rhs._tpos; //(rhs._fpos + HRCORE_FP_BITS_BASE) / -HRCORE_FP_BITS_PER_DIGIT;
262 if (i >= n) {
263 i = n;
264 } else {
265 r = ret->at(i);
266 if (i)
267 *ret->prev(r).data += (*r.data >= 5);
268 }
269 r = ret->prev(r);
270 for (; i > 0; --i, r = ret->prev(r)) { // Remove last 0s
271 if (*r.data != 0)
272 break;
273 }
274 if (i > 0 && *r.data == 10) { // Overflow! may be a number that has fixed digit
275 --i;
276 auto j = ret->prev(r);
277 while (j) {
278 if (*j.data == 9) {
279 --i;
280 j = ret->prev(j);
281 } else {
282 ++*j.data;
283 break;
284 }
285 }
286 }
287 Integer k = rhs.make() = 1;
288 r = ret->begin();
289 auto& x = *r.data;
290 if (x != 0) { // Process overflow to integer
291 if (x > 10)
293 if (x == 10) {
294 it = it + k;
295 x = 0;
296 }
297 }
298 operator<<(os, it); // Output integer part
299 if (i == 0) {
300 if (os.flags() & std::ios_base::showpoint) {
301 os << ".0";
302 }
303 } else {
304 os << '.';
305 for (size_t x = 0; x < i; ++x, r = ret->next(r)) {
306 os << *r.data;
307 }
308 }
309 } else {
310 operator<<(os, it);
311 if (os.flags() & std::ios_base::showpoint) {
312 os << ".0";
313 }
314 }
315 return os;
316 }
317
318#endif
319}
320
321#if HRCORE_ENABLE_UTILS
326namespace Utils {
327
328 Value::Integer abs(const Value::Integer& s)
329 {
330 auto ret = s;
331 ret.positive(true);
332 return ret;
333 }
334#if HRCORE_ENABLE_FP
335 Value::Float abs(const Value::Float& s)
336 {
337 auto ret = s;
338 ret.positive(true);
339 return ret;
340 }
341#endif
342}
343
344#if HRCORE_ENABLE_UTILS_IO
345
346namespace Internal {
347 template <typename G>
349
350 template <>
351 struct _expression_isT_OK<Value::Integer> {
352 using value = Value::Integer;
353 };
354
355 template <>
356 struct _expression_isT_OK<Value::Float> {
357 using value = Value::Float;
358 };
359
360 template <typename G>
362 static G mod(const G& l, const G& r)
363 {
364 (void)l, (void)r;
366 }
367 };
368
369 template <>
370 struct _expression_mod<Value::Integer> {
371 static Value::Integer mod(Value::Integer& l, const Value::Integer& r)
372 {
373 return l % r;
374 }
375 };
376
377 int8_t _getOp(char c)
378 {
379 switch (c) {
380 case '+':
381 return 0;
382 case '-':
383 return 1;
384 case '*':
385 return 2;
386 case '/':
387 return 3;
388 case '%':
389 return 4;
390 default:
391 return -1;
392 }
393 }
394
395 constexpr bool _isOpPrior(int8_t left, int8_t right)
396 {
397 return (left >= 0 && right >= 0) && !(left < 2 && right > 1);
398 }
399}
400
401namespace Utils {
402
410 template <typename T, typename U>
411 class Expression;
412
420 template <typename T, typename U>
421 std::istream& operator>>(std::istream& is, Expression<T, U>& rhs);
422
427 template <typename T, typename U>
428 std::ostream& operator<<(std::ostream& os, Expression<T, U>& rhs);
429
430 template <typename T, typename U>
432 private:
433 using _dummy_t = typename Internal::_expression_isT_OK<T>::value; // Error here? Type of T using is not supported!
434 struct node_t {
435 T* data = nullptr;
436 uint8_t sgn = 0xFF; // 0 - add, 1 - sub, 2 - mul, 3 - div, 4 - mod
437 };
438 T* _result = nullptr;
439 std::deque<node_t> _data;
440 Storage::Interface* _helper = nullptr;
441 bool _isEval = false;
442 bool _evalFailed = false;
443
444 Storage::Interface* _newStorage()
445 {
446 if (this->_helper)
447 return this->_helper->newObject();
448 return new U;
449 }
450
451 static T _doOperation(T& left, T& right, uint8_t op)
452 {
453 switch (op) {
454 case 0:
455 return left + right;
456 case 1:
457 return left - right;
458 case 2:
459 return left * right;
460 case 3:
461 return left / right;
462 case 4: {
463 return Internal::_expression_mod<T>::mod(left, right);
464 }
465 default:
467 }
468 }
469
470 public:
471 Expression(U* helper = nullptr)
472 {
473 this->_helper = dynamic_cast<Storage::Interface*>(helper); // Error here? U is invalid!
474 }
476 {
477 for (auto x = this->_data.begin(); x != this->_data.end(); ++x) {
478 if ((*x).data)
479 delete (*x).data;
480 }
481 if(this->_result)
482 delete this->_result;
483 }
484
491 bool eval()
492 {
493 this->_isEval = true;
494 this->_evalFailed = true;
495 std::stack<T*> tmp;
496 for (auto x = this->_data.begin(); x != this->_data.end(); ++x) {
497 if ((*x).data) {
498 tmp.push((*x).data);
499 continue;
500 }
501 uint8_t op = (*x).sgn;
502 if (!tmp.size())
503 return false;
504 T* right = tmp.top();
505 tmp.pop();
506 if (!tmp.size())
507 return false;
508 T* left = tmp.top();
509 HRCORE_DBG(std::cout << *left << ' ' << int(op) << ' ' << *right << std::endl;)
510 *left = _doOperation(*left, *right, op);
511 }
512 if (tmp.size() == 1) {
513 if(this->_result)
514 delete this->_result;
515 this->_result = tmp.top();
516 this->_evalFailed = false;
517 return true;
518 }
519 return false;
520 }
521
526 return *this->_result;
527 }
528
529 friend std::istream& operator>><>(std::istream& is, Expression<T, U>& rhs);
530 friend std::ostream& operator<< <>(std::ostream& os, Expression<T, U>& rhs);
531 };
532
533 template <typename T, typename U>
534 std::istream& operator>>(std::istream& is, Expression<T, U>& rhs)
535 {
536 int c = EOF;
537 int8_t op = -8; // Initialized
538 int num = 0;
539 // int numOp = 0;
540 bool nextNeg = false;
541 std::stack<int8_t> tmp;
542 while ((c = is.peek()) != EOF) {
543 typename Expression<T, U>::node_t ret;
544 while (c == ' ' || c == '\n' || c == '\r') {
545 is.ignore();
546 c = is.peek();
547 }
548 c = is.get();
549 HRCORE_DBG(std::cout << int(c) << std::endl;)
550 if (c == EOF)
551 break;
552 if (c >= '0' && c <= '9') {
553 is.putback(c);
554 if (op == -1) // Continous number
556 T& in = *new T(rhs._newStorage(), true, true, false);
557 operator>>(is, in);
558 if (nextNeg) {
559 in.positive(false);
560 nextNeg = false;
561 }
562 ret.data = &in;
563 rhs._data.push_back(ret);
564 ++num;
565 op = -1;
566 continue;
567 }
568 // Process '(' and ')'
569 if (c == '(') {
570 tmp.push(-2); // using -2 as '('
571 op = -2;
572 continue;
573 }
574 if (c == ')') {
575 while (tmp.size() && tmp.top() != -2) {
576 ret.sgn = tmp.top();
577 rhs._data.push_back(ret);
578 tmp.pop();
579 }
580 if (!tmp.size())
582 tmp.pop(); // Pop '('
583 op = -1;
584 continue;
585 }
586 int8_t x = Internal::_getOp(c);
587 if (x > -1) { // A operator
588 if (op != -1) { // Last time is an operator
589 if (x == 1 && op != 1) {
590 nextNeg = true;
591 op = x;
592 continue;
593 } else {
595 }
596 }
597 op = x;
598 while (tmp.size() && Internal::_isOpPrior(tmp.top(), x)) {
599 ret.sgn = tmp.top();
600 rhs._data.push_back(ret);
601 tmp.pop();
602 }
603 tmp.push(x);
604 continue;
605 }
607 }
608 while (tmp.size()) {
609 typename Expression<T, U>::node_t ret;
610 ret.sgn = tmp.top();
611 rhs._data.push_back(ret);
612 tmp.pop();
613 }
614 return is;
615 }
616
617 template <typename T, typename U>
618 std::ostream& operator<<(std::ostream& os, Expression<T, U>& rhs)
619 {
620 if (!rhs._isEval)
621 rhs.eval();
622 if (!rhs._evalFailed) {
623 operator<<(os, *(rhs._result));
624 }
625 return os;
626 }
627} // namespace Utils
628#endif
629
630#endif
631
632} // namespace HRCore
633
634#endif
Exception os Expression failed to convert.
Definition: HRCore.h:253
Exception of Expression evaluation: Invalid operation on seleted data type.
Definition: HRCore.h:255
Exception of internal error. Please dig into it and solve.
Definition: HRCore.h:241
A class as a storage interface, pure virtual.
Definition: StorageIF.hpp:28
virtual Interface * newObject()=0
Get a new object of same type.
virtual size_t length()=0
Get the length of storage.
virtual bool shrink(size_t len)=0
Remove data from the end to shrink the size to a given length.
virtual bool extend(size_t len)=0
Extend the storage to a given length.
virtual item_t next(item_t cur)=0
Get next item.
virtual item_t end()=0
Returns the last item of storage.
virtual item_t begin()=0
Return the first item of storage.
virtual item_t prev(item_t cur)=0
A class to get and evaluate expression.
Definition: Utils.hpp:431
T getResult()
Get the Result object. Make sure eval() returned true first, otherwise Segment Fault!
Definition: Utils.hpp:525
bool eval()
Evaluate the expression.
Definition: Utils.hpp:491
Float type.
Definition: Value.hpp:648
static Integer make()
Construct a new Integer object using given type of Storage::Interface implement.
Definition: Value.hpp:109
Integer getInteger()
Get Interger section.
Definition: Value.hpp:791
Integer type.
Definition: Value.hpp:27
static Integer make()
Construct a new Integer object using given type of Storage::Interface implement.
Definition: Value.hpp:109
static bool _absGreater(const Integer &l, const Integer &r)
Examine if l > r.
Definition: Value.hpp:510
DivisionResult_t divideBy(const Integer &r)
A function to calculate (*this / r)
Definition: Value.hpp:279
bool positive() const
Return the sign of object.
Definition: Value.hpp:380
#define HRCORE_FP_BITS_BASE
Decide how many bits as a base of Float. Default: 24.
Definition: HRCore.h:84
#define HRCORE_FP_BITS_PER_DIGIT
Decide how many bits for a digit in Float. Default: 8.
Definition: HRCore.h:94
std::ostream & operator<<(std::ostream &os, Integer &rhs)
Reload of operator<< to support std::cout and other std::ostream with Integer.
Definition: Utils.hpp:56
std::istream & operator>>(std::istream &is, Integer &rhs)
Reload of operator>> to support std::cin and other std::istream with Integer.
Definition: Utils.hpp:119
std::ostream & operator<<(std::ostream &os, Expression< T, U > &rhs)
Output the value of an expression.
Definition: Utils.hpp:618
std::istream & operator>>(std::istream &is, Expression< T, U > &rhs)
Convert a stream into an expression.
Definition: Utils.hpp:534
bool _prepareNextStorageItem(Storage::Interface *i, Storage::Interface::item_t &r)
Prepare next item of Storage to be writen.
Definition: Utils.hpp:21
HRCore main namespace, contains all classes.
Definition: LinkedList.hpp:14
Storage item descriptor.
Definition: StorageIF.hpp:32