Skip to content

Commit f7e940b

Browse files
committed
Improve parse_number
1 parent ee367ab commit f7e940b

File tree

2 files changed

+148
-144
lines changed

2 files changed

+148
-144
lines changed

include/jsoncons/json_parser.hpp

Lines changed: 138 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,201 +1712,195 @@ class basic_json_parser : public ser_context
17121712
JSONCONS_UNREACHABLE();
17131713
}
17141714
minus_sign:
1715-
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
1715+
if (jsoncons::utility::is_nonzero_digit(*input_ptr_))
17161716
{
1717-
number_state_ = parse_number_state::minus;
1718-
return;
1717+
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1718+
++input_ptr_;
1719+
++position_;
1720+
goto integer;
17191721
}
1720-
switch (*input_ptr_)
1722+
if (*input_ptr_ == '0')
17211723
{
1722-
case '0':
1723-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1724-
++input_ptr_;
1725-
++position_;
1726-
goto zero;
1727-
case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1728-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1729-
++input_ptr_;
1730-
++position_;
1731-
goto integer;
1732-
default:
1733-
err_handler_(json_errc::invalid_number, *this);
1734-
ec = json_errc::expected_value;
1735-
more_ = false;
1736-
return;
1724+
string_buffer_.push_back('0');
1725+
++input_ptr_;
1726+
++position_;
1727+
goto zero;
17371728
}
1729+
err_handler_(json_errc::invalid_number, *this);
1730+
ec = json_errc::invalid_number;
1731+
more_ = false;
1732+
return;
17381733
zero:
17391734
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
17401735
{
1741-
number_state_ = parse_number_state::zero;
1736+
number_state_ = parse_number_state::integer;
17421737
return;
17431738
}
1744-
switch (*input_ptr_)
1739+
if (*input_ptr_ == '.')
17451740
{
1746-
case '.':
1747-
string_buffer_.push_back('.');
1748-
++input_ptr_;
1749-
++position_;
1750-
goto fraction1;
1751-
case 'e':case 'E':
1752-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1753-
++input_ptr_;
1754-
++position_;
1755-
goto exp1;
1756-
case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1757-
err_handler_(json_errc::leading_zero, *this);
1758-
ec = json_errc::leading_zero;
1759-
more_ = false;
1760-
number_state_ = parse_number_state::zero;
1761-
return;
1762-
default:
1763-
end_integer_value(visitor, ec);
1764-
if (JSONCONS_UNLIKELY(ec)) return;
1765-
//state_ = parse_state::expect_comma_or_end;
1766-
return;
1741+
string_buffer_.push_back('.');
1742+
++input_ptr_;
1743+
++position_;
1744+
goto fraction1;
17671745
}
1768-
integer:
1769-
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
1746+
if (*input_ptr_ == 'e' || *input_ptr_ == 'E')
17701747
{
1771-
number_state_ = parse_number_state::integer;
1748+
string_buffer_.push_back('e');
1749+
++input_ptr_;
1750+
++position_;
1751+
goto exp1;
1752+
}
1753+
if (jsoncons::utility::is_digit(*input_ptr_))
1754+
{
1755+
err_handler_(json_errc::leading_zero, *this);
1756+
ec = json_errc::leading_zero;
1757+
more_ = false;
1758+
number_state_ = parse_number_state::zero;
17721759
return;
17731760
}
1774-
switch (*input_ptr_)
1761+
end_integer_value(visitor, ec);
1762+
return;
1763+
integer:
1764+
while (true)
17751765
{
1776-
case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1777-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1778-
++input_ptr_;
1779-
++position_;
1780-
goto integer;
1781-
case '.':
1782-
string_buffer_.push_back('.');
1783-
++input_ptr_;
1784-
++position_;
1785-
goto fraction1;
1786-
case 'e':case 'E':
1787-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1788-
++input_ptr_;
1789-
++position_;
1790-
goto exp1;
1791-
default:
1792-
end_integer_value(visitor, ec);
1793-
if (JSONCONS_UNLIKELY(ec)) return;
1794-
//state_ = parse_state::expect_comma_or_end;
1766+
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
1767+
{
1768+
number_state_ = parse_number_state::integer;
17951769
return;
1770+
}
1771+
if (JSONCONS_UNLIKELY(!jsoncons::utility::is_digit(*input_ptr_)))
1772+
{
1773+
break;
1774+
}
1775+
string_buffer_.push_back(*input_ptr_);
1776+
++input_ptr_;
1777+
++position_;
1778+
}
1779+
if (*input_ptr_ == '.')
1780+
{
1781+
string_buffer_.push_back('.');
1782+
++input_ptr_;
1783+
++position_;
1784+
goto fraction1;
1785+
}
1786+
if (*input_ptr_ == 'e' || *input_ptr_ == 'E')
1787+
{
1788+
string_buffer_.push_back(*input_ptr_);
1789+
++input_ptr_;
1790+
++position_;
1791+
goto exp1;
17961792
}
1793+
end_integer_value(visitor, ec);
1794+
return;
17971795
fraction1:
17981796
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
17991797
{
18001798
number_state_ = parse_number_state::fraction1;
18011799
return;
18021800
}
1803-
switch (*input_ptr_)
1801+
if (jsoncons::utility::is_digit(*input_ptr_))
18041802
{
1805-
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1806-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1807-
++input_ptr_;
1808-
++position_;
1809-
goto fraction2;
1810-
default:
1811-
err_handler_(json_errc::invalid_number, *this);
1812-
ec = json_errc::invalid_number;
1813-
more_ = false;
1814-
number_state_ = parse_number_state::fraction1;
1815-
return;
1803+
string_buffer_.push_back(*input_ptr_);
1804+
++input_ptr_;
1805+
++position_;
1806+
goto fraction2;
18161807
}
1808+
err_handler_(json_errc::invalid_number, *this);
1809+
ec = json_errc::invalid_number;
1810+
more_ = false;
1811+
number_state_ = parse_number_state::fraction1;
1812+
return;
18171813
fraction2:
1818-
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
1814+
while (true)
18191815
{
1820-
number_state_ = parse_number_state::fraction2;
1821-
return;
1816+
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
1817+
{
1818+
number_state_ = parse_number_state::fraction2;
1819+
return;
1820+
}
1821+
if (JSONCONS_UNLIKELY(!jsoncons::utility::is_digit(*input_ptr_)))
1822+
{
1823+
break;
1824+
}
1825+
string_buffer_.push_back(*input_ptr_);
1826+
++input_ptr_;
1827+
++position_;
18221828
}
1823-
switch (*input_ptr_)
1829+
if (*input_ptr_ == 'e' || *input_ptr_ == 'E')
18241830
{
1825-
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1826-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1827-
++input_ptr_;
1828-
++position_;
1829-
goto fraction2;
1830-
case 'e':case 'E':
1831-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1832-
++input_ptr_;
1833-
++position_;
1834-
goto exp1;
1835-
default:
1836-
end_fraction_value(visitor, ec);
1837-
if (JSONCONS_UNLIKELY(ec)) return;
1838-
return;
1831+
string_buffer_.push_back(*input_ptr_);
1832+
++input_ptr_;
1833+
++position_;
1834+
goto exp1;
18391835
}
1836+
end_fraction_value(visitor, ec);
1837+
return;
18401838
exp1:
18411839
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
18421840
{
18431841
number_state_ = parse_number_state::exp1;
18441842
return;
18451843
}
1846-
switch (*input_ptr_)
1844+
if (*input_ptr_ == '-')
18471845
{
1848-
case '+':
1849-
++input_ptr_;
1850-
++position_;
1851-
goto exp2;
1852-
case '-':
1853-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1854-
++input_ptr_;
1855-
++position_;
1856-
goto exp2;
1857-
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1858-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1859-
++input_ptr_;
1860-
++position_;
1861-
goto exp3;
1862-
default:
1863-
err_handler_(json_errc::invalid_number, *this);
1864-
ec = json_errc::expected_value;
1865-
more_ = false;
1866-
number_state_ = parse_number_state::exp1;
1867-
return;
1846+
string_buffer_.push_back('-');
1847+
++input_ptr_;
1848+
++position_;
1849+
goto exp2;
1850+
}
1851+
if (jsoncons::utility::is_digit(*input_ptr_))
1852+
{
1853+
string_buffer_.push_back(*input_ptr_);
1854+
++input_ptr_;
1855+
++position_;
1856+
goto exp3;
1857+
}
1858+
if (*input_ptr_ == '+')
1859+
{
1860+
++input_ptr_;
1861+
++position_;
1862+
goto exp2;
18681863
}
1864+
err_handler_(json_errc::invalid_number, *this);
1865+
ec = json_errc::invalid_number;
1866+
more_ = false;
1867+
return;
18691868
exp2:
18701869
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
18711870
{
18721871
number_state_ = parse_number_state::exp2;
18731872
return;
18741873
}
1875-
switch (*input_ptr_)
1874+
if (jsoncons::utility::is_digit(*input_ptr_))
18761875
{
1877-
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1878-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1879-
++input_ptr_;
1880-
++position_;
1881-
goto exp3;
1882-
default:
1883-
err_handler_(json_errc::invalid_number, *this);
1884-
ec = json_errc::expected_value;
1885-
more_ = false;
1886-
number_state_ = parse_number_state::exp2;
1887-
return;
1876+
string_buffer_.push_back(*input_ptr_);
1877+
++input_ptr_;
1878+
++position_;
1879+
goto exp3;
18881880
}
1881+
err_handler_(json_errc::invalid_number, *this);
1882+
ec = json_errc::invalid_number;
1883+
more_ = false;
1884+
return;
18891885

18901886
exp3:
1891-
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
1892-
{
1893-
number_state_ = parse_number_state::exp3;
1894-
return;
1895-
}
1896-
switch (*input_ptr_)
1887+
while (true)
18971888
{
1898-
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':
1899-
string_buffer_.push_back(static_cast<char>(*input_ptr_));
1900-
++input_ptr_;
1901-
++position_;
1902-
goto exp3;
1903-
default:
1904-
end_fraction_value(visitor, ec);
1905-
if (JSONCONS_UNLIKELY(ec)) return;
1889+
if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted
1890+
{
1891+
number_state_ = parse_number_state::exp3;
19061892
return;
1893+
}
1894+
if (JSONCONS_UNLIKELY(!jsoncons::utility::is_digit(*input_ptr_)))
1895+
{
1896+
break;
1897+
}
1898+
string_buffer_.push_back(*input_ptr_);
1899+
++input_ptr_;
1900+
++position_;
19071901
}
1908-
1909-
JSONCONS_UNREACHABLE();
1902+
end_fraction_value(visitor, ec);
1903+
return;
19101904
}
19111905

19121906
void parse_string(basic_json_visitor<char_type>& visitor, std::error_code& ec)

include/jsoncons/utility/to_number.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ constexpr bool is_digit(wchar_t d)
3535
return d >= '0' && d <= '9';
3636
}
3737

38+
constexpr bool is_nonzero_digit(char d)
39+
{
40+
return d >= '1' && d <= '9';
41+
}
42+
43+
constexpr bool is_nonzero_digit(wchar_t d)
44+
{
45+
return d >= '1' && d <= '9';
46+
}
47+
3848
template <typename CharT>
3949
struct to_number_result
4050
{

0 commit comments

Comments
 (0)