mirror of
https://github.com/boostorg/json.git
synced 2026-02-10 23:42:19 +00:00
Use sse2 for number parsing
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
# ifdef _MSC_VER
|
||||
# define BOOST_JSON_FORCEINLINE __forceinline
|
||||
# else
|
||||
# define BOOST_JSON_FORCEINLINE
|
||||
# define BOOST_JSON_FORCEINLINE inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/error.hpp>
|
||||
#include <boost/json/number.hpp>
|
||||
#include <cstdint>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
@@ -63,17 +63,17 @@ public:
|
||||
maybe_init(char ch) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
size_t
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
size_t size,
|
||||
error_code& ec) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
size_t
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
size_t size,
|
||||
error_code& ec) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <boost/json/detail/ieee_parser.hpp>
|
||||
#include <boost/json/detail/assert.hpp>
|
||||
#include <boost/json/detail/sse2.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
@@ -44,11 +45,11 @@ maybe_init(char ch) noexcept
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size_t
|
||||
ieee_parser::
|
||||
write_some(
|
||||
char const* const data,
|
||||
std::size_t const size,
|
||||
size_t const size,
|
||||
error_code& ec) noexcept
|
||||
{
|
||||
auto p = data;
|
||||
@@ -80,48 +81,26 @@ loop:
|
||||
ec = error::expected_mantissa;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
if(d == 0)
|
||||
{
|
||||
++p;
|
||||
st_ = state::frac1;
|
||||
goto loop;
|
||||
}
|
||||
// 64-bit unsigned is at most 20 digits
|
||||
if(p1 - p < 18)
|
||||
if(p1 - p < 16)
|
||||
{
|
||||
++p;
|
||||
dec_.mantissa = d;
|
||||
st_ = state::mant2;
|
||||
goto loop;
|
||||
}
|
||||
// fast loop
|
||||
unsigned long long m = d;
|
||||
for(int i = 0; i < 18; ++i)
|
||||
{
|
||||
d = *p - '0';
|
||||
if(d < 10)
|
||||
{
|
||||
m = 10 * m + d;
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
if(*p == '.')
|
||||
{
|
||||
++p;
|
||||
dec_.mantissa = m;
|
||||
st_ = state::frac2;
|
||||
goto loop;
|
||||
}
|
||||
if(*p == 'e' || *p == 'E')
|
||||
{
|
||||
++p;
|
||||
dec_.mantissa = m;
|
||||
st_ = state::exp1;
|
||||
goto loop;
|
||||
}
|
||||
st_ = state::done;
|
||||
goto finish;
|
||||
}
|
||||
dec_.mantissa = m;
|
||||
// fast path
|
||||
auto const result =
|
||||
detail::parse_unsigned(
|
||||
dec_.mantissa, p);
|
||||
dec_.mantissa = result.m;
|
||||
p += result.n;
|
||||
st_ = state::mant2;
|
||||
BOOST_FALLTHROUGH;
|
||||
}
|
||||
@@ -190,23 +169,49 @@ loop:
|
||||
{
|
||||
if(p >= p1)
|
||||
break;
|
||||
unsigned char const d = *p - '0';
|
||||
if(d >= 10)
|
||||
// three digits or less
|
||||
if( dec_.mantissa < 1000 &&
|
||||
p1 - p >= 16)
|
||||
{
|
||||
ec = error::expected_fraction;
|
||||
break;
|
||||
}
|
||||
auto tmp = dec_.mantissa * 10 + d;
|
||||
if(dec_.mantissa < tmp)
|
||||
{
|
||||
--off_;
|
||||
dec_.mantissa = tmp;
|
||||
// fast path
|
||||
auto const result =
|
||||
parse_unsigned(dec_.mantissa, p);
|
||||
if(result.n == 0)
|
||||
{
|
||||
ec = error::expected_fraction;
|
||||
break;
|
||||
}
|
||||
p += result.n;
|
||||
off_ -= static_cast<short>(result.n);
|
||||
if(result.n < 16)
|
||||
{
|
||||
dec_.mantissa = result.m;
|
||||
dec_.exponent = off_;
|
||||
st_ = state::done;
|
||||
goto finish;
|
||||
}
|
||||
dec_.mantissa = result.m;
|
||||
}
|
||||
else
|
||||
{
|
||||
// limit of precision
|
||||
unsigned char const d = *p - '0';
|
||||
if(d >= 10)
|
||||
{
|
||||
ec = error::expected_fraction;
|
||||
break;
|
||||
}
|
||||
auto tmp = dec_.mantissa * 10 + d;
|
||||
if(dec_.mantissa < tmp)
|
||||
{
|
||||
--off_;
|
||||
dec_.mantissa = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// limit of precision
|
||||
}
|
||||
++p;
|
||||
}
|
||||
++p;
|
||||
st_ = state::frac3;
|
||||
BOOST_FALLTHROUGH;
|
||||
}
|
||||
@@ -363,11 +368,11 @@ finish:
|
||||
return p - p0;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size_t
|
||||
ieee_parser::
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
size_t size,
|
||||
error_code& ec) noexcept
|
||||
{
|
||||
auto n = write_some(data, size, ec);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//
|
||||
// Copyright (c) 2019 Peter Dimov (pdimov at gmail dot com)
|
||||
// Copyright (c) 2019 Peter Dimov (pdimov at gmail dot com),
|
||||
// Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,21 +12,41 @@
|
||||
#define BOOST_JSON_DETAIL_SSE2_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <stdint.h>
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
#include <emmintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
# include <emmintrin.h>
|
||||
# include <xmmintrin.h>
|
||||
# ifdef _MSC_VER
|
||||
# include <intrin.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
struct parse_unsigned_result
|
||||
{
|
||||
uint64_t m;
|
||||
int n;
|
||||
};
|
||||
|
||||
inline
|
||||
unsigned long long
|
||||
bool
|
||||
operator==(
|
||||
parse_unsigned_result const& lhs,
|
||||
parse_unsigned_result const& rhs) noexcept
|
||||
{
|
||||
return lhs.m == rhs.m && lhs.n == rhs.n;
|
||||
}
|
||||
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
|
||||
inline
|
||||
size_t
|
||||
count_unescaped(
|
||||
char const* s,
|
||||
unsigned long long n) noexcept
|
||||
size_t n) noexcept
|
||||
{
|
||||
__m128i const q1 = _mm_set1_epi8( '"' );
|
||||
__m128i const q2 = _mm_set1_epi8( '\\' );
|
||||
@@ -71,10 +92,51 @@ count_unescaped(
|
||||
return s - s0;
|
||||
};
|
||||
|
||||
// assumes p..p+15 are valid
|
||||
inline
|
||||
parse_unsigned_result
|
||||
parse_unsigned( uint64_t r, char const* p ) noexcept
|
||||
{
|
||||
__m128i const q1 = _mm_set1_epi8( '0' );
|
||||
__m128i const q2 = _mm_set1_epi8( '9' );
|
||||
|
||||
__m128i v1 = _mm_loadu_si128( (__m128i const*)p );
|
||||
|
||||
v1 = _mm_or_si128(
|
||||
_mm_cmplt_epi8( v1, q1 ),
|
||||
_mm_cmpgt_epi8( v1, q2 ) );
|
||||
|
||||
int m = _mm_movemask_epi8( v1 );
|
||||
|
||||
int n;
|
||||
|
||||
if( m == 0 )
|
||||
{
|
||||
n = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
n = __builtin_ffs( m ) - 1;
|
||||
#else
|
||||
unsigned long index;
|
||||
_BitScanForward( &index, m );
|
||||
n = index;
|
||||
#endif
|
||||
}
|
||||
|
||||
for( int i = 0; i < n; ++i )
|
||||
{
|
||||
r = r * 10 + p[ i ] - '0';
|
||||
}
|
||||
|
||||
return { r, n };
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline
|
||||
unsigned long long
|
||||
size_t
|
||||
count_unescaped(
|
||||
char const*,
|
||||
unsigned long long) noexcept
|
||||
@@ -82,6 +144,21 @@ count_unescaped(
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline
|
||||
parse_unsigned_result
|
||||
parse_unsigned( uint64_t r, char const* p ) noexcept
|
||||
{
|
||||
int n = 0;
|
||||
for(; n< 16; ++n )
|
||||
{
|
||||
unsigned char const d = *p++ - '0';
|
||||
if(d > 9)
|
||||
break;
|
||||
r = r * 10 + d;
|
||||
}
|
||||
return { r, n };
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define BOOST_JSON_NUMBER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
@@ -19,7 +20,7 @@ namespace json {
|
||||
*/
|
||||
struct ieee_decimal
|
||||
{
|
||||
unsigned long long mantissa;
|
||||
uint64_t mantissa;
|
||||
short exponent;
|
||||
bool sign;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user