use tinyusdz::str::parse_int

This commit is contained in:
Syoyo
2025-07-26 07:08:56 +09:00
parent c07d4dae6a
commit 5cf79781d1
7 changed files with 153 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
all:
clang++-17 -O2 -g -stdlib=libc++ parse_int.cc -o parse_int
clang++ -O2 -g -stdlib=libc++ parse_int.cc -o parse_int ../../src/tiny-string.cc
clean:
rm -f parse_int a.out
@@ -9,4 +9,4 @@ test: all
./parse_int 1000000 1 4
./parse_int 1000000 1 8
.PHONY: all clean test
.PHONY: all clean test

View File

@@ -8,6 +8,8 @@
#include <random>
#include <charconv>
#include "../../src/tiny-string.hh"
std::string gen_intarray(size_t n, bool delim_at_end) {
std::stringstream ss;
std::random_device rd;
@@ -333,8 +335,8 @@ bool do_parse(
while ((j = cnt++) < results.size()) {
int64_t val;
auto answer = std::from_chars(spans[j].p_begin, spans[j].p_begin + spans[j].length, val);
if (answer.ec != std::errc()) {
tinyusdz::tstring_view ts(spans[j].p_begin, size_t(spans[j].length));
if (!tinyusdz::str::parse_int64(ts, &val)) {
parse_failed = true;
}
@@ -355,8 +357,8 @@ bool do_parse(
} else {
for (size_t i = 0; i < spans.size(); i++) {
int64_t val;
auto answer = std::from_chars(spans[i].p_begin, spans[i].p_begin + spans[i].length, val);
if (answer.ec != std::errc()) {
tinyusdz::tstring_view ts(spans[i].p_begin, size_t(spans[i].length));
if (!tinyusdz::str::parse_int64(ts, &val)) {
std::cerr << "parsing failure\n";
return false;
}
@@ -416,4 +418,4 @@ int main(int argc, char **argv) {
do_parse(nthreads, lex_results, parse_results);
return 0;
}
}

View File

@@ -400,7 +400,7 @@ bool parse_int64(const tstring_view &sv, int64_t *ret) {
if (str[i] < '0' || str[i] > '9') {
return false;
}
result = result * 10 + (str[i] - '0');
result = result * 10ull + uint64_t(str[i] - '0');
// Check for overflow
if (negative && result > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1) {
@@ -437,7 +437,7 @@ bool parse_uint(const tstring_view &sv, uint32_t *ret) {
if (str[i] < '0' || str[i] > '9') {
return false;
}
result = result * 10 + (str[i] - '0');
result = result * 10 + uint64_t(str[i] - '0');
// Check for overflow
if (result > std::numeric_limits<uint32_t>::max()) {
@@ -473,11 +473,11 @@ bool parse_uint64(const tstring_view &sv, uint64_t *ret) {
}
// Check for overflow before multiplication
if (result > (std::numeric_limits<uint64_t>::max() - (str[i] - '0')) / 10) {
if (result > (std::numeric_limits<uint64_t>::max() - uint64_t(str[i] - '0')) / 10) {
return false;
}
result = result * 10 + (str[i] - '0');
result = result * 10 + uint64_t(str[i] - '0');
}
*ret = result;
@@ -714,7 +714,7 @@ bool parse_int_arary(const tstring_view &sv, std::vector<int32_t> *result, const
p++;
}
if (p == num_start) {
if (p <= num_start) {
return false; // No number found
}
@@ -722,7 +722,7 @@ bool parse_int_arary(const tstring_view &sv, std::vector<int32_t> *result, const
int32_t value;
tstring_view num_view(num_start);
// Create a temporary view with the correct length
size_t num_len = p - num_start;
size_t num_len = size_t(p - num_start);
std::string num_str(num_start, num_len);
tstring_view temp_view(num_str.c_str());
if (!parse_int(temp_view, &value)) {

View File

@@ -171,6 +171,11 @@ struct tstring_view {
_s = s;
}
constexpr tstring_view(const char *s, size_t n) {
_len = n;
_s = s;
}
tstring_view(const std::string &s) : tstring_view(s.c_str()) {
}

View File

@@ -38,6 +38,7 @@ TEST_LIST = {
{ "ioutil_test", ioutil_test },
{ "strutil_test", strutil_test },
{ "tinystring_test", tinystring_test },
{ "parse_int_test", parse_int_test },
{ "timesamples_test", timesamples_test },
#if defined(TINYUSDZ_WITH_PXR_COMPAT_API)
{ "pxr_compat_api_test", pxr_compat_api_test },

View File

@@ -66,3 +66,134 @@ void tinystring_test(void) {
TEST_CHECK(v4.ends_with(v2));
}
void parse_int_test(void) {
using namespace tinyusdz::str;
int32_t result;
// Basic positive numbers
{
tstring_view sv("123");
TEST_CHECK(parse_int(sv, &result));
TEST_CHECK(result == 123);
}
// Basic negative numbers
{
tstring_view sv("-456");
TEST_CHECK(parse_int(sv, &result));
TEST_CHECK(result == -456);
}
// Zero
{
tstring_view sv("0");
TEST_CHECK(parse_int(sv, &result));
TEST_CHECK(result == 0);
}
// Positive sign
{
tstring_view sv("+789");
TEST_CHECK(parse_int(sv, &result));
TEST_CHECK(result == 789);
}
// Maximum int32_t value
{
tstring_view sv("2147483647");
TEST_CHECK(parse_int(sv, &result));
TEST_CHECK(result == 2147483647);
}
// Minimum int32_t value
{
tstring_view sv("-2147483648");
TEST_CHECK(parse_int(sv, &result));
TEST_CHECK(result == -2147483648);
}
// Empty string
{
tstring_view sv("");
TEST_CHECK(!parse_int(sv, &result));
}
// Just a sign
{
tstring_view sv("-");
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("+");
TEST_CHECK(!parse_int(sv, &result));
}
// Non-numeric characters
{
tstring_view sv("123a");
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("a123");
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("12.3");
TEST_CHECK(!parse_int(sv, &result));
}
// Overflow cases
{
tstring_view sv("2147483648"); // INT32_MAX + 1
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("-2147483649"); // INT32_MIN - 1
TEST_CHECK(!parse_int(sv, &result));
}
// Very large numbers
{
tstring_view sv("999999999999999999");
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("-999999999999999999");
TEST_CHECK(!parse_int(sv, &result));
}
// Leading/trailing spaces (should fail since parse_int doesn't handle whitespace)
{
tstring_view sv(" 123");
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("123 ");
TEST_CHECK(!parse_int(sv, &result));
}
// Multiple signs
{
tstring_view sv("++123");
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("--123");
TEST_CHECK(!parse_int(sv, &result));
}
{
tstring_view sv("+-123");
TEST_CHECK(!parse_int(sv, &result));
}
}

View File

@@ -2,3 +2,4 @@
void strutil_test(void);
void tinystring_test(void);
void parse_int_test(void);