Resource Tuner
Loading...
Searching...
No Matches
SafeOps.h
1// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
2// SPDX-License-Identifier: BSD-3-Clause-Clear
3
4#ifndef SAFE_OPS_H
5#define SAFE_OPS_H
6
7#include <climits>
8#include <limits>
9#include <stdexcept>
10
11/*******************************************
12Note: Arguments must be of the same types,
13 i.e. no implict conversions
14******************************************** */
15enum OperationStatus {
16 SUCCESS,
17 OVERFLOW,
18 UNDERFLOW,
19 DIVISION_BY_ZERO
20};
21
22// Return max or min limit.
23template <typename T>
24T Add(T firstArg, T secondArg, OperationStatus& status) {
25 status = SUCCESS;
26 // Both arguments are +ve
27 if(firstArg >= 0 && secondArg >= 0 && ((std::numeric_limits<T>::max() - firstArg) < secondArg)) {
28 status = OperationStatus::OVERFLOW;
29 return std::numeric_limits<T>::max();
30 }
31 // Both arguments are -ve
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();
35 }
36 return firstArg + secondArg;
37}
38
39template <typename T>
40T Subtract(T firstArg, T secondArg, OperationStatus& status) {
41 status = SUCCESS;
42 //Only opposite signed arguments will cause undesired behaviour
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();
49 }
50
51 return firstArg - secondArg;
52}
53
54template <typename T>
55T Multiply(T firstArg, T secondArg, OperationStatus& status) {
56 status = SUCCESS;
57
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();
70 }
71
72 return firstArg * secondArg;
73}
74
75template <typename T>
76T Divide(T firstArg, T secondArg, OperationStatus& status) {
77 status = OperationStatus::SUCCESS;
78 if(secondArg == 0) {
79 status = DIVISION_BY_ZERO;
80 return firstArg;
81 }
82
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();
95 }
96
97 return firstArg / secondArg;
98}
99
100#define SafeDeref(ptr) \
101 (ptr == nullptr) ? throw std::invalid_argument("Null Pointer Dereference") : *ptr
102
103#define SafeAssignment(ptr, val) \
104 (ptr == nullptr) ? throw std::invalid_argument("Null Pointer Assignment") : *ptr = val
105
106#define SafeStaticCast(ptr, to) \
107 (ptr == nullptr) ? throw std::invalid_argument("Null Pointer Casting") : static_cast<to>(ptr)
108
109#define ASSIGN_AND_INCR(ptr, val) \
110 SafeAssignment(ptr, val); \
111 ptr++; \
112
113#define DEREF_AND_INCR(ptr, type) ({ \
114 type val = (type)(SafeDeref(ptr)); \
115 ptr++; \
116 val; \
117})
118
119#define VALIDATE_GT(val, base) \
120 (val > base) ? val : throw std::invalid_argument("Invalid value: " #val " should be greater than " #base)
121
122#define VALIDATE_GE(val, base) \
123 (val >= base) ? val : throw std::invalid_argument("Invalid value: " #val " should be greater or equal to " #base)
124
125#endif