Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser suspend after event #1045

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions bench/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import notfile ;
import os ;
import path ;
import property ;
import bench.jam ;

path-constant HERE : . ;

Expand Down Expand Up @@ -68,8 +69,12 @@ rule run-bench ( target : sources * : props * )
}
LAUNCHER on $(target) = $(launcher) ;

local files = [ property.select bench.file : $(props) ] ;
FILES on $(target) = $(files:G=) ;
local files ;
for local f in [ property.select bench.file : $(props) ]
{
files += [ $(f:G=).actualize ] ;
}
FILES on $(target) = $(files) ;

local dir = [ on $(target) return $(LOCATE) ] ;
if $(dir)
Expand All @@ -81,7 +86,7 @@ rule run-bench ( target : sources * : props * )
}
}

actions run-bench
actions run-bench bind FILES
{
$(LAUNCHER)$(>) $(FLAGS) $(FILES)
}
2 changes: 1 addition & 1 deletion bench/bench.jam
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import feature ;

feature.feature bench.option : : free optional ;
feature.feature bench.launcher : : free optional ;
feature.feature bench.file : : free optional ;
feature.feature bench.file : : free dependency optional ;
247 changes: 125 additions & 122 deletions include/boost/json/basic_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,124 @@

namespace boost {
namespace json {
namespace detail {

struct number
{
uint64_t mant;
int bias;
int exp;
bool frac;
bool neg;
};

enum class parser_state : char
{
doc1, doc3,
com1, com2, com3, com4,
lit1,
str1, str2, str3, str4,
str5, str6, str7, str8,
sur1, sur2, sur3,
sur4, sur5, sur6,
obj1, obj2, obj3, obj4,
obj5, obj6, obj7, obj8,
obj9, obj10, obj11,
arr1, arr2, arr3,
arr4, arr5, arr6,
num1, num2, num3, num4,
num5, num6, num7, num8,
exp1, exp2, exp3,
val1, val2, val3,

com_stop1, com_stop2, com_stop3, com_stop4, com_stop5,
lit_stop1,
str_stop1, str_stop2, str_stop3, str_stop4,
esc_stop1, esc_stop2, esc_stop3,
obj_stop1, obj_stop2,
arr_stop1, arr_stop2,
num_stop1, num_stop2, num_stop3, num_stop4, num_stop5, num_stop6,
num_stop7, num_stop8, num_stop9, num_stop10, num_stop11, num_stop12,
num_stop13,
doc_stop1,
};

struct parser_data
{
number num_;
system::error_code ec;
detail::stack st;
parse_options opt;
// how many levels deeper the parser can go
std::size_t depth_left;
char const* end;
bool more; // false for final buffer
bool done = false; // true on complete parse

inline
void reserve();

// The sentinel value is returned by parse functions
// to indicate that the parser failed, or suspended.
// this is used as it is distinct from all valid values
// for data in write
inline
char const*
sentinel() noexcept
{
// the "+1" ensures that the returned pointer is unique even if
// the given input buffer borders on this object
return reinterpret_cast<char const*>(this) + 1;
}

std::size_t
depth() const noexcept
{
return opt.max_depth - depth_left;
}

BOOST_JSON_DECL
char const*
stop(char const* p) noexcept;

BOOST_JSON_DECL
char const*
continue_stop(parser_state s);

BOOST_JSON_DECL
char const*
continue_stop(parser_state s, std::size_t n);

BOOST_JSON_DECL
char const*
fail(char const* p, error ev, source_location const* loc) noexcept;

BOOST_JSON_DECL
char const*
maybe_suspend(char const* p, parser_state s);

BOOST_JSON_DECL
char const*
maybe_suspend(char const* p, parser_state s, std::size_t n);

BOOST_JSON_DECL
char const*
maybe_suspend(char const* p, parser_state s, number const& num);

BOOST_JSON_DECL
char const*
suspend(char const* p, parser_state s);

BOOST_JSON_DECL
char const*
suspend(char const* p, parser_state s, std::size_t n);

BOOST_JSON_DECL
char const*
suspend(char const* p, parser_state s, number const& num);
};

} // namespace detail

/** An incremental SAX parser for serialized JSON.

Expand Down Expand Up @@ -263,134 +381,26 @@ namespace json {
template<class Handler>
class basic_parser
{
enum class state : char
{
doc1, doc3,
com1, com2, com3, com4,
lit1,
str1, str2, str3, str4,
str5, str6, str7, str8,
sur1, sur2, sur3,
sur4, sur5, sur6,
obj1, obj2, obj3, obj4,
obj5, obj6, obj7, obj8,
obj9, obj10, obj11,
arr1, arr2, arr3,
arr4, arr5, arr6,
num1, num2, num3, num4,
num5, num6, num7, num8,
exp1, exp2, exp3,
val1, val2, val3
};

struct number
{
uint64_t mant;
int bias;
int exp;
bool frac;
bool neg;
};
using state = detail::parser_state;
using number = detail::number;

template< bool StackEmpty_, char First_ >
struct parse_number_helper;

// optimization: must come first
Handler h_;

number num_;
system::error_code ec_;
detail::stack st_;
detail::parser_data data_;
detail::utf8_sequence seq_;
unsigned u1_;
unsigned u2_;
bool more_; // false for final buffer
bool done_ = false; // true on complete parse
bool clean_ = true; // write_some exited cleanly
const char* end_;
detail::sbo_buffer<16 + 16 + 1 + 1> num_buf_;
parse_options opt_;
// how many levels deeper the parser can go
std::size_t depth_ = opt_.max_depth;
unsigned char cur_lit_ = 0;
unsigned char lit_offset_ = 0;

inline void reserve();
inline const char* sentinel();
inline bool incomplete(
const detail::const_stream_wrapper& cs);

#ifdef __INTEL_COMPILER
#pragma warning push
#pragma warning disable 2196
#endif

BOOST_NOINLINE
inline
const char*
suspend_or_fail(state st);

BOOST_NOINLINE
inline
const char*
suspend_or_fail(
state st,
std::size_t n);

BOOST_NOINLINE
inline
const char*
fail(const char* p) noexcept;

BOOST_NOINLINE
inline
const char*
fail(
const char* p,
error ev,
source_location const* loc) noexcept;

BOOST_NOINLINE
inline
const char*
maybe_suspend(
const char* p,
state st);

BOOST_NOINLINE
inline
const char*
maybe_suspend(
const char* p,
state st,
std::size_t n);

BOOST_NOINLINE
inline
const char*
maybe_suspend(
const char* p,
state st,
const number& num);

BOOST_NOINLINE
inline
const char*
suspend(
const char* p,
state st);

BOOST_NOINLINE
inline
const char*
suspend(
const char* p,
state st,
const number& num);

#ifdef __INTEL_COMPILER
#pragma warning pop
#endif
bool
incomplete(detail::const_stream_wrapper const& cs);

template<bool StackEmpty_/*, bool Terminal_*/>
const char* parse_comment(const char* p,
Expand Down Expand Up @@ -460,13 +470,6 @@ class basic_parser
std::integral_constant<char, First_> first,
std::integral_constant<number_precision, Numbers_> numbers);

// intentionally private
std::size_t
depth() const noexcept
{
return opt_.max_depth - depth_;
}

public:
/// Copy constructor (deleted)
basic_parser(
Expand Down Expand Up @@ -567,7 +570,7 @@ class basic_parser
system::error_code
last_error() const noexcept
{
return ec_;
return data_.ec;
}

/** Return true if a complete JSON has been parsed.
Expand All @@ -591,7 +594,7 @@ class basic_parser
bool
done() const noexcept
{
return done_;
return data_.done;
}

/** Reset the state, to parse a new document.
Expand Down
Loading
Loading