24T Add(T firstArg, T secondArg, OperationStatus& status) {
27 if(firstArg >= 0 && secondArg >= 0 && ((std::numeric_limits<T>::max() - firstArg) < secondArg)) {
28 status = OperationStatus::OVERFLOW;
29 return std::numeric_limits<T>::max();
32 else if(firstArg < 0 && secondArg < 0 && ((std::numeric_limits<T>::lowest() - firstArg) > secondArg)) {
33 status = OperationStatus::UNDERFLOW;
34 return std::numeric_limits<T>::lowest();
36 return firstArg + secondArg;
40T Subtract(T firstArg, T secondArg, OperationStatus& status) {
43 if(firstArg >= 0 && secondArg < 0 && ((firstArg - std::numeric_limits<T>::max()) > secondArg)) {
44 status = OperationStatus::OVERFLOW;
45 return std::numeric_limits<T>::max();
46 }
else if(firstArg < 0 && secondArg >=0 && ((firstArg - std::numeric_limits<T>::lowest()) < secondArg)) {
47 status = OperationStatus::UNDERFLOW;
48 return std::numeric_limits<T>::lowest();
51 return firstArg - secondArg;
55T Multiply(T firstArg, T secondArg, OperationStatus& status) {
58 if(firstArg > 0 && secondArg >0 && ((std::numeric_limits<T>::max() / firstArg) < secondArg)) {
59 status = OperationStatus::OVERFLOW;
60 return std::numeric_limits<T>::max();
61 }
else if(firstArg < 0 && secondArg < 0 && ((std::numeric_limits<T>::max() / firstArg) > secondArg)) {
62 status = OperationStatus::OVERFLOW;
63 return std::numeric_limits<T>::max();
64 }
else if(firstArg > 0 && secondArg < 0 && ((std::numeric_limits<T>::lowest() / firstArg) > secondArg)) {
65 status = OperationStatus::UNDERFLOW;
66 return std::numeric_limits<T>::lowest();
67 }
else if(firstArg < 0 && secondArg > 0 && ((std::numeric_limits<T>::lowest() / firstArg) < secondArg)) {
68 status = OperationStatus::UNDERFLOW;
69 return std::numeric_limits<T>::lowest();
72 return firstArg * secondArg;
76T Divide(T firstArg, T secondArg, OperationStatus& status) {
77 status = OperationStatus::SUCCESS;
79 status = DIVISION_BY_ZERO;
83 if(secondArg > 0 && secondArg < 1 && firstArg > 0 && ((std::numeric_limits<T>::max() * secondArg) < firstArg)) {
84 status = OperationStatus::OVERFLOW;
85 return std::numeric_limits<T>::max();
86 }
else if(secondArg > 0 && secondArg < 1 && firstArg < 0 && ((std::numeric_limits<T>::lowest() * secondArg) > firstArg)) {
87 status = OperationStatus::UNDERFLOW;
88 return std::numeric_limits<T>::lowest();
89 }
else if(secondArg < 0 && secondArg > -1 && firstArg > 0 && ((std::numeric_limits<T>::lowest() * secondArg) < firstArg)) {
90 status = OperationStatus::UNDERFLOW;
91 return std::numeric_limits<T>::lowest();
92 }
else if(secondArg < 0 && secondArg > -1 && firstArg < 0 && ((std::numeric_limits<T>::max() * secondArg) > firstArg)) {
93 status = OperationStatus::OVERFLOW;
94 return std::numeric_limits<T>::max();
97 return firstArg / secondArg;
100#define SafeDeref(ptr) \
101 (ptr == nullptr) ? throw std::invalid_argument("Null Pointer Dereference") : *ptr
103#define SafeAssignment(ptr, val) \
104 (ptr == nullptr) ? throw std::invalid_argument("Null Pointer Assignment") : *ptr = val
106#define SafeStaticCast(ptr, to) \
107 (ptr == nullptr) ? throw std::invalid_argument("Null Pointer Casting") : static_cast<to>(ptr)
109#define ASSIGN_AND_INCR(ptr, val) \
110 SafeAssignment(ptr, val); \
113#define DEREF_AND_INCR(ptr, type) ({ \
114 type val = (type)(SafeDeref(ptr)); \
119#define VALIDATE_GT(val, base) \
120 (val > base) ? val : throw std::invalid_argument("Invalid value: " #val " should be greater than " #base)
122#define VALIDATE_GE(val, base) \
123 (val >= base) ? val : throw std::invalid_argument("Invalid value: " #val " should be greater or equal to " #base)