Skip to content

Commit 83bb6ba

Browse files
committed
Replace ParseNumber
* ParseFloat * ParseNormalFloat * ParseInteger
1 parent 6c99263 commit 83bb6ba

File tree

5 files changed

+265
-36
lines changed

5 files changed

+265
-36
lines changed

source/opt/set_spec_constant_default_value_pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ namespace {
3535
using utils::EncodeNumberStatus;
3636
using utils::NumberType;
3737
using utils::ParseAndEncodeNumber;
38-
using utils::ParseNumber;
38+
using utils::ParseInteger;
3939

4040
// Given a numeric value in a null-terminated c string and the expected type of
4141
// the value, parses the string and encodes it in a vector of words. If the
@@ -332,7 +332,7 @@ SetSpecConstantDefaultValuePass::ParseDefaultValuesString(const char* str) {
332332
const char* entry_end = str;
333333
std::string spec_id_str(entry_begin, entry_end - entry_begin);
334334
uint32_t spec_id = 0;
335-
if (!ParseNumber(spec_id_str.c_str(), &spec_id)) {
335+
if (!ParseInteger(spec_id_str.c_str(), &spec_id)) {
336336
// The spec id is not a valid uint32 number.
337337
return nullptr;
338338
}

source/text.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ spv_result_t encodeImmediate(spvtools::AssemblyContext* context,
163163
const char* text, spv_instruction_t* pInst) {
164164
assert(*text == '!');
165165
uint32_t parse_result;
166-
if (!spvtools::utils::ParseNumber(text + 1, &parse_result)) {
166+
if (!spvtools::utils::ParseInteger(text + 1, &parse_result)) {
167167
return context->diagnostic(SPV_ERROR_INVALID_TEXT)
168168
<< "Invalid immediate integer: !" << text + 1;
169169
}

source/text_handler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ const IdType kUnknownType = {0, false, IdTypeClass::kBottom};
157157
uint32_t AssemblyContext::spvNamedIdAssignOrGet(const char* textValue) {
158158
if (!ids_to_preserve_.empty()) {
159159
uint32_t id = 0;
160-
if (spvtools::utils::ParseNumber(textValue, &id)) {
160+
if (spvtools::utils::ParseInteger(textValue, &id)) {
161161
if (ids_to_preserve_.find(id) != ids_to_preserve_.end()) {
162162
bound_ = std::max(bound_, id + 1);
163163
return id;
@@ -389,7 +389,7 @@ std::set<uint32_t> AssemblyContext::GetNumericIds() const {
389389
std::set<uint32_t> ids;
390390
for (const auto& kv : named_ids_) {
391391
uint32_t id;
392-
if (spvtools::utils::ParseNumber(kv.first.c_str(), &id)) ids.insert(id);
392+
if (spvtools::utils::ParseInteger(kv.first.c_str(), &id)) ids.insert(id);
393393
}
394394
return ids;
395395
}

source/util/parse_number.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ EncodeNumberStatus ParseAndEncodeIntegerNumber(
9191
if (is_negative) {
9292
int64_t decoded_signed = 0;
9393

94-
if (!ParseNumber(text, &decoded_signed)) {
94+
if (!ParseInteger(text, &decoded_signed)) {
9595
ErrorMsgStream(error_msg) << "Invalid signed integer literal: " << text;
9696
return EncodeNumberStatus::kInvalidText;
9797
}
@@ -107,7 +107,7 @@ EncodeNumberStatus ParseAndEncodeIntegerNumber(
107107
decoded_bits = decoded_signed;
108108
} else {
109109
// There's no leading minus sign, so parse it as an unsigned integer.
110-
if (!ParseNumber(text, &decoded_bits)) {
110+
if (!ParseInteger(text, &decoded_bits)) {
111111
ErrorMsgStream(error_msg) << "Invalid unsigned integer literal: " << text;
112112
return EncodeNumberStatus::kInvalidText;
113113
}
@@ -148,7 +148,7 @@ EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
148148
switch (bit_width) {
149149
case 16: {
150150
HexFloat<FloatProxy<Float16>> hVal(0);
151-
if (!ParseNumber(text, &hVal)) {
151+
if (!ParseFloat(text, &hVal)) {
152152
ErrorMsgStream(error_msg) << "Invalid 16-bit float literal: " << text;
153153
return EncodeNumberStatus::kInvalidText;
154154
}
@@ -161,7 +161,7 @@ EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
161161
} break;
162162
case 32: {
163163
HexFloat<FloatProxy<float>> fVal(0.0f);
164-
if (!ParseNumber(text, &fVal)) {
164+
if (!ParseFloat(text, &fVal)) {
165165
ErrorMsgStream(error_msg) << "Invalid 32-bit float literal: " << text;
166166
return EncodeNumberStatus::kInvalidText;
167167
}
@@ -170,7 +170,7 @@ EncodeNumberStatus ParseAndEncodeFloatingPointNumber(
170170
} break;
171171
case 64: {
172172
HexFloat<FloatProxy<double>> dVal(0.0);
173-
if (!ParseNumber(text, &dVal)) {
173+
if (!ParseFloat(text, &dVal)) {
174174
ErrorMsgStream(error_msg) << "Invalid 64-bit float literal: " << text;
175175
return EncodeNumberStatus::kInvalidText;
176176
}

source/util/parse_number.h

Lines changed: 255 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -160,40 +160,269 @@ bool CheckRangeAndIfHexThenSignExtend(T value, const NumberType& type,
160160
return true;
161161
}
162162

163+
#include <cstdlib>
164+
#include <climits>
165+
163166
// Parses a numeric value of a given type from the given text. The number
164167
// should take up the entire string, and should be within bounds for the target
165168
// type. On success, returns true and populates the object referenced by
166169
// value_pointer. On failure, returns false.
167-
template <typename T>
168-
bool ParseNumber(const char* text, T* value_pointer) {
169-
// C++11 doesn't define std::istringstream(int8_t&), so calling this method
170-
// with a single-byte type leads to implementation-defined behaviour.
171-
// Similarly for uint8_t.
172-
static_assert(sizeof(T) > 1,
173-
"Single-byte types are not supported in this parse method");
170+
// template <typename T>
171+
// bool ParseNumber(const char* text, T* value_pointer) {
172+
// // C++11 doesn't define std::istringstream(int8_t&), so calling this method
173+
// // with a single-byte type leads to implementation-defined behaviour.
174+
// // Similarly for uint8_t.
175+
// static_assert(sizeof(T) > 1,
176+
// "Single-byte types are not supported in this parse method");
177+
178+
// if (!text) return false;
179+
// std::istringstream text_stream(text);
180+
// // Allow both decimal and hex input for integers.
181+
// // It also allows octal input, but we don't care about that case.
182+
// text_stream >> std::setbase(0);
183+
// text_stream >> *value_pointer;
184+
185+
// // We should have read something.
186+
// bool ok = (text[0] != 0) && !text_stream.bad();
187+
// // It should have been all the text.
188+
// ok = ok && text_stream.eof();
189+
// // It should have been in range.
190+
// ok = ok && !text_stream.fail();
191+
192+
// // Work around a bug in the GNU C++11 library. It will happily parse
193+
// // "-1" for uint16_t as 65535.
194+
// if (ok && text[0] == '-')
195+
// ok = !ClampToZeroIfUnsignedType<T>::Clamp(value_pointer);
196+
197+
// return ok;
198+
// }
199+
200+
template <typename T, typename Traits>
201+
inline bool ParseFloat(const char* text, HexFloat<T, Traits>* value);
202+
203+
inline bool ParseNormalFloat(const char* text, float* value_pointer) {
204+
if (!text) return false;
205+
206+
char* end = nullptr;
207+
errno = 0;
208+
auto parsed = std::strtof(text, &end);
209+
210+
if ((errno == ERANGE && (parsed == HUGE_VALF || parsed == -HUGE_VALF)) || (errno != 0 && parsed == 0)) {
211+
return false;
212+
}
213+
214+
if (end == text || end[0] != 0) {
215+
return false;
216+
}
217+
218+
*value_pointer = parsed;
219+
return true;
220+
}
221+
222+
inline bool ParseNormalFloat(const char* text, double* value_pointer) {
223+
if (!text) return false;
224+
225+
char* end = nullptr;
226+
errno = 0;
227+
auto parsed = std::strtod(text, &end);
228+
229+
if ((errno == ERANGE && (parsed == HUGE_VAL || parsed == -HUGE_VAL)) || (errno != 0 && parsed == 0)) {
230+
return false;
231+
}
232+
233+
if (end == text || end[0] != 0) {
234+
return false;
235+
}
236+
237+
*value_pointer = parsed;
238+
return true;
239+
}
240+
241+
template <>
242+
inline bool ParseFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
243+
const char* text,
244+
HexFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>* value_pointer) {
245+
float parsed;
246+
if (!ParseNormalFloat(text, &parsed)) {
247+
return false;
248+
}
249+
250+
HexFloat<FloatProxy<float>> float_val(parsed);
251+
float_val.castTo(*value_pointer, round_direction::kToZero);
252+
253+
if (Float16::isInfinity(value_pointer->value().getAsFloat())) {
254+
value_pointer->set_value(value_pointer->isNegative() ? Float16::lowest() : Float16::max());
255+
return false;
256+
}
257+
258+
return true;
259+
}
260+
261+
template<>
262+
inline bool ParseFloat<FloatProxy<float>, HexFloatTraits<FloatProxy<float>>>(
263+
const char* text,
264+
HexFloat<FloatProxy<float>, HexFloatTraits<FloatProxy<float>>>* value_pointer) {
265+
float parsed;
266+
if (!ParseNormalFloat(text, &parsed)) {
267+
return false;
268+
}
269+
270+
value_pointer->set_value(parsed);
271+
return true;
272+
}
273+
274+
template<>
275+
inline bool ParseFloat<FloatProxy<double>, HexFloatTraits<FloatProxy<double>>>(
276+
const char* text,
277+
HexFloat<FloatProxy<double>, HexFloatTraits<FloatProxy<double>>>* value_pointer) {
278+
double parsed;
279+
if (!ParseNormalFloat(text, &parsed)) {
280+
return false;
281+
}
282+
283+
value_pointer->set_value(parsed);
284+
return true;
285+
}
286+
287+
inline bool ParseInteger(const char* text, uint16_t* value_pointer) {
288+
if (!text || text[0] == '-') return false;
289+
290+
char* end = nullptr;
291+
errno = 0;
292+
auto parsed = std::strtoul(text, &end, 0);
293+
294+
if ((errno == ERANGE && parsed == ULONG_MAX) || (errno != 0 && parsed == 0)) {
295+
return false;
296+
}
297+
298+
if (end == text || end[0] != 0) {
299+
return false;
300+
}
301+
302+
if (parsed > std::numeric_limits<uint16_t>::max() || parsed < std::numeric_limits<uint16_t>::min()) {
303+
return false;
304+
}
305+
306+
*value_pointer = static_cast<uint16_t>(parsed);
307+
return true;
308+
}
309+
310+
inline bool ParseInteger(const char* text, int16_t* value_pointer) {
311+
if (!text) return false;
174312

313+
char* end = nullptr;
314+
errno = 0;
315+
auto parsed = std::strtol(text, &end, 0);
316+
317+
if ((errno == ERANGE && (parsed == LONG_MAX || parsed == LONG_MIN)) || (errno != 0 && parsed == 0)) {
318+
return false;
319+
}
320+
321+
if (end == text || end[0] != 0) {
322+
return false;
323+
}
324+
325+
if (parsed > std::numeric_limits<int16_t>::max() || parsed < std::numeric_limits<int16_t>::min()) {
326+
return false;
327+
}
328+
329+
*value_pointer = static_cast<int16_t>(parsed);
330+
return true;
331+
}
332+
333+
inline bool ParseInteger(const char* text, uint32_t* value_pointer) {
334+
if (!text || text[0] == '-') return false;
335+
336+
char* end = nullptr;
337+
errno = 0;
338+
auto parsed = std::strtoul(text, &end, 0);
339+
340+
if ((errno == ERANGE && parsed == ULONG_MAX) || (errno != 0 && parsed == 0)) {
341+
return false;
342+
}
343+
344+
if (end == text || end[0] != 0) {
345+
return false;
346+
}
347+
348+
if (parsed > std::numeric_limits<uint32_t>::max() || parsed < std::numeric_limits<uint32_t>::min()) {
349+
return false;
350+
}
351+
352+
*value_pointer = static_cast<uint32_t>(parsed);
353+
return true;
354+
}
355+
356+
inline bool ParseInteger(const char* text, int32_t* value_pointer) {
175357
if (!text) return false;
176-
std::istringstream text_stream(text);
177-
// Allow both decimal and hex input for integers.
178-
// It also allows octal input, but we don't care about that case.
179-
text_stream >> std::setbase(0);
180-
text_stream >> *value_pointer;
181-
182-
// We should have read something.
183-
bool ok = (text[0] != 0) && !text_stream.bad();
184-
// It should have been all the text.
185-
ok = ok && text_stream.eof();
186-
// It should have been in range.
187-
ok = ok && !text_stream.fail();
188-
189-
// Work around a bug in the GNU C++11 library. It will happily parse
190-
// "-1" for uint16_t as 65535.
191-
if (ok && text[0] == '-')
192-
ok = !ClampToZeroIfUnsignedType<T>::Clamp(value_pointer);
193-
194-
return ok;
358+
359+
char* end = nullptr;
360+
errno = 0;
361+
auto parsed = std::strtol(text, &end, 0);
362+
363+
if ((errno == ERANGE && (parsed == LONG_MAX || parsed == LONG_MIN)) || (errno != 0 && parsed == 0)) {
364+
return false;
365+
}
366+
367+
if (end == text || end[0] != 0) {
368+
return false;
369+
}
370+
371+
if (parsed > std::numeric_limits<int32_t>::max() || parsed < std::numeric_limits<int32_t>::min()) {
372+
return false;
373+
}
374+
375+
*value_pointer = static_cast<int32_t>(parsed);
376+
return true;
377+
}
378+
379+
inline bool ParseInteger(const char* text, int64_t* value_pointer) {
380+
if (!text) return false;
381+
382+
char* end = nullptr;
383+
errno = 0;
384+
auto parsed = std::strtoll(text, &end, 0);
385+
386+
if ((errno == ERANGE && (parsed == LLONG_MAX || parsed == LLONG_MIN)) || (errno != 0 && parsed == 0)) {
387+
return false;
388+
}
389+
390+
if (end == text || end[0] != 0) {
391+
return false;
392+
}
393+
394+
if (parsed > std::numeric_limits<int64_t>::max() || parsed < std::numeric_limits<int64_t>::min()) {
395+
return false;
396+
}
397+
398+
*value_pointer = static_cast<int64_t>(parsed);
399+
return true;
195400
}
196401

402+
inline bool ParseInteger(const char* text, uint64_t* value_pointer) {
403+
if (!text || text[0] == '-') return false;
404+
405+
char* end = nullptr;
406+
errno = 0;
407+
auto parsed = std::strtoull(text, &end, 0);
408+
409+
if ((errno == ERANGE && parsed == ULLONG_MAX) || (errno != 0 && parsed == 0)) {
410+
return false;
411+
}
412+
413+
if (end == text || end[0] != 0) {
414+
return false;
415+
}
416+
417+
if (parsed > std::numeric_limits<uint64_t>::max() || parsed < std::numeric_limits<uint64_t>::min()) {
418+
return false;
419+
}
420+
421+
*value_pointer = static_cast<uint64_t>(parsed);
422+
return true;
423+
}
424+
425+
197426
// Enum to indicate the parsing and encoding status.
198427
enum class EncodeNumberStatus {
199428
kSuccess = 0,

0 commit comments

Comments
 (0)