1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ASSEMBLER_UTILS_NUMBER_UTILS_H
17#define ASSEMBLER_UTILS_NUMBER_UTILS_H
18
19namespace panda::pandasm {
20
21constexpr size_t HEX_BASE = 16;
22
23constexpr size_t DEC_BASE = 10;
24
25constexpr size_t OCT_BASE = 8;
26
27constexpr size_t BIN_BASE = 2;
28
29constexpr size_t MAX_DWORD = 65536;
30
31inline bool IsHexNumber(const std::string_view &token)
32{
33    for (auto i : token) {
34        if (!((i >= '0' && i <= '9') || (i >= 'A' && i <= 'F') || (i >= 'a' && i <= 'f'))) {
35            return false;
36        }
37    }
38    return true;
39}
40
41inline bool IsBinaryNumber(const std::string_view &token)
42{
43    for (auto i : token) {
44        if (!(i == '0' || i == '1')) {
45            return false;
46        }
47    }
48    return true;
49}
50
51inline bool IsOctalNumber(const std::string_view &token)
52{
53    for (auto i : token) {
54        if (!(i >= '0' && i <= '7')) {
55            return false;
56        }
57    }
58    return true;
59}
60
61inline bool ValidateInteger(const std::string_view &p)
62{
63    constexpr size_t GENERAL_SHIFT = 2;
64
65    std::string_view token = p;
66
67    if (token.back() == '-' || token.back() == '+' || token.back() == 'x' || token == ".") {
68        return false;
69    }
70
71    if (token[0] == '-' || token[0] == '+') {
72        token.remove_prefix(1);
73    }
74
75    if (token[0] == '0' && token.size() > 1 && token.find('.') == std::string::npos) {
76        if (token[1] == 'x') {
77            token.remove_prefix(GENERAL_SHIFT);
78            return IsHexNumber(token);
79        }
80
81        if (token[1] == 'b') {
82            token.remove_prefix(GENERAL_SHIFT);
83            return (!token.empty() && IsBinaryNumber(token));
84        }
85
86        if (token[1] >= '0' && token[1] <= '9' && token.find('e') == std::string::npos) {
87            token.remove_prefix(1);
88            return IsOctalNumber(token);
89        }
90    }
91
92    for (auto i : token) {
93        if (!(i >= '0' && i <= '9')) {
94            return false;
95        }
96    }
97
98    return true;
99}
100
101inline int64_t IntegerNumber(std::string_view p)
102{
103    constexpr size_t GENERAL_SHIFT = 2;
104
105    // expects a valid number
106    if (p.size() == 1) {
107        return p[0] - '0';
108    }
109
110    size_t minus_shift = 0;
111    if (p[0] == '-') {
112        minus_shift++;
113    }
114
115    if (p[minus_shift + 1] == 'b') {
116        p.remove_prefix(GENERAL_SHIFT + minus_shift);
117        return std::strtoull(p.data(), nullptr, BIN_BASE) * (minus_shift == 0 ? 1 : -1);
118    }
119
120    if (p[minus_shift + 1] == 'x') {
121        return std::strtoull(p.data(), nullptr, HEX_BASE);
122    }
123
124    if (p[minus_shift] == '0') {
125        return std::strtoull(p.data(), nullptr, OCT_BASE);
126    }
127
128    return std::strtoull(p.data(), nullptr, DEC_BASE);
129}
130
131inline bool ValidateFloat(const std::string_view &p)
132{
133    std::string_view token = p;
134
135    if (ValidateInteger(token)) {
136        return true;
137    }
138
139    if (token[0] == '-' || token[0] == '+') {
140        token.remove_prefix(1);
141    }
142
143    bool dot = false;
144    bool exp = false;
145    bool nowexp = false;
146
147    for (auto i : token) {
148        if (nowexp && (i == '-' || i == '+')) {
149            nowexp = false;
150            continue;
151        }
152
153        if (nowexp) {
154            nowexp = false;
155        }
156
157        if (i == '.' && !exp && !dot) {
158            dot = true;
159        } else if (!exp && i == 'e') {
160            nowexp = true;
161            exp = true;
162        } else if (!(i >= '0' && i <= '9')) {
163            return false;
164        }
165    }
166
167    return !nowexp;
168}
169
170inline double FloatNumber(std::string_view p, bool is_64bit)
171{
172    constexpr size_t GENERAL_SHIFT = 2;
173    // expects a valid number
174    if (p.size() > GENERAL_SHIFT && p.substr(0, GENERAL_SHIFT) == "0x") {  // hex literal
175        char *end = nullptr;
176        if (is_64bit) {
177            return bit_cast<double>(strtoull(p.data(), &end, 0));
178        } else {
179            return bit_cast<float>(static_cast<uint32_t>(strtoull(p.data(), &end, 0)));
180        }
181    }
182    return std::strtold(std::string(p.data(), p.length()).c_str(), nullptr);
183}
184
185inline size_t ToNumber(std::string_view p)
186{
187    size_t sum = 0;
188
189    for (char i : p) {
190        if (isdigit(i) != 0) {
191            sum = sum * DEC_BASE + static_cast<size_t>(i - '0');
192        } else {
193            return MAX_DWORD;
194        }
195    }
196
197    return sum;
198}
199
200}  // namespace panda::pandasm
201
202#endif  // ASSEMBLER_UTILS_NUMBER_UTILS_H
203