2
0
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:
Vinnie Falco
2019-11-03 09:51:17 -08:00
parent 6257953b99
commit 938bdf7158
6 changed files with 145 additions and 209 deletions

View File

@@ -48,7 +48,7 @@
# ifdef _MSC_VER
# define BOOST_JSON_FORCEINLINE __forceinline
# else
# define BOOST_JSON_FORCEINLINE
# define BOOST_JSON_FORCEINLINE inline
# endif
#endif

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
};