mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-04 14:37:46 +00:00
Added thirdparty: boost library
This commit is contained in:
+1765
File diff suppressed because it is too large
Load Diff
+715
@@ -0,0 +1,715 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_BASIC_PARSER_HPP
|
||||
#define BOOST_JSON_BASIC_PARSER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <boost/json/error.hpp>
|
||||
#include <boost/json/kind.hpp>
|
||||
#include <boost/json/parse_options.hpp>
|
||||
#include <boost/json/detail/stack.hpp>
|
||||
#include <boost/json/detail/stream.hpp>
|
||||
#include <boost/json/detail/utf8.hpp>
|
||||
#include <boost/json/detail/sbo_buffer.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** An incremental SAX parser for serialized JSON.
|
||||
|
||||
This implements a SAX-style parser, invoking a
|
||||
caller-supplied handler with each parsing event.
|
||||
To use, first declare a variable of type
|
||||
`basic_parser<T>` where `T` meets the handler
|
||||
requirements specified below. Then call
|
||||
@ref write_some one or more times with the input,
|
||||
setting `more = false` on the final buffer.
|
||||
The parsing events are realized through member
|
||||
function calls on the handler, which exists
|
||||
as a data member of the parser.
|
||||
\n
|
||||
The parser may dynamically allocate intermediate
|
||||
storage as needed to accommodate the nesting level
|
||||
of the input JSON. On subsequent invocations, the
|
||||
parser can cheaply re-use this memory, improving
|
||||
performance. This storage is freed when the
|
||||
parser is destroyed
|
||||
|
||||
@par Usage
|
||||
|
||||
To get the declaration and function definitions
|
||||
for this class it is necessary to include this
|
||||
file instead:
|
||||
@code
|
||||
#include <boost/json/basic_parser_impl.hpp>
|
||||
@endcode
|
||||
|
||||
Users who wish to parse JSON into the DOM container
|
||||
@ref value will not use this class directly; instead
|
||||
they will create an instance of @ref parser or
|
||||
@ref stream_parser and use that instead. Alternatively,
|
||||
they may call the function @ref parse. This class is
|
||||
designed for users who wish to perform custom actions
|
||||
instead of building a @ref value. For example, to
|
||||
produce a DOM from an external library.
|
||||
\n
|
||||
@note
|
||||
|
||||
By default, only conforming JSON using UTF-8
|
||||
encoding is accepted. However, select non-compliant
|
||||
syntax can be allowed by construction using a
|
||||
@ref parse_options set to desired values.
|
||||
|
||||
@par Handler
|
||||
|
||||
The handler provided must be implemented as an
|
||||
object of class type which defines each of the
|
||||
required event member functions below. The event
|
||||
functions return a `bool` where `true` indicates
|
||||
success, and `false` indicates failure. If the
|
||||
member function returns `false`, it must set
|
||||
the error code to a suitable value. This error
|
||||
code will be returned by the write function to
|
||||
the caller.
|
||||
\n
|
||||
Handlers are required to declare the maximum
|
||||
limits on various elements. If these limits
|
||||
are exceeded during parsing, then parsing
|
||||
fails with an error.
|
||||
\n
|
||||
The following declaration meets the parser's
|
||||
handler requirements:
|
||||
|
||||
@code
|
||||
struct handler
|
||||
{
|
||||
/// The maximum number of elements allowed in an array
|
||||
static constexpr std::size_t max_array_size = -1;
|
||||
|
||||
/// The maximum number of elements allowed in an object
|
||||
static constexpr std::size_t max_object_size = -1;
|
||||
|
||||
/// The maximum number of characters allowed in a string
|
||||
static constexpr std::size_t max_string_size = -1;
|
||||
|
||||
/// The maximum number of characters allowed in a key
|
||||
static constexpr std::size_t max_key_size = -1;
|
||||
|
||||
/// Called once when the JSON parsing begins.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_document_begin( error_code& ec );
|
||||
|
||||
/// Called when the JSON parsing is done.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_document_end( error_code& ec );
|
||||
|
||||
/// Called when the beginning of an array is encountered.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_array_begin( error_code& ec );
|
||||
|
||||
/// Called when the end of the current array is encountered.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param n The number of elements in the array.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_array_end( std::size_t n, error_code& ec );
|
||||
|
||||
/// Called when the beginning of an object is encountered.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_object_begin( error_code& ec );
|
||||
|
||||
/// Called when the end of the current object is encountered.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param n The number of elements in the object.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_object_end( std::size_t n, error_code& ec );
|
||||
|
||||
/// Called with characters corresponding to part of the current string.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param s The partial characters
|
||||
/// @param n The total size of the string thus far
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_string_part( string_view s, std::size_t n, error_code& ec );
|
||||
|
||||
/// Called with the last characters corresponding to the current string.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param s The remaining characters
|
||||
/// @param n The total size of the string
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_string( string_view s, std::size_t n, error_code& ec );
|
||||
|
||||
/// Called with characters corresponding to part of the current key.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param s The partial characters
|
||||
/// @param n The total size of the key thus far
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_key_part( string_view s, std::size_t n, error_code& ec );
|
||||
|
||||
/// Called with the last characters corresponding to the current key.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param s The remaining characters
|
||||
/// @param n The total size of the key
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_key( string_view s, std::size_t n, error_code& ec );
|
||||
|
||||
/// Called with the characters corresponding to part of the current number.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param s The partial characters
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_number_part( string_view s, error_code& ec );
|
||||
|
||||
/// Called when a signed integer is parsed.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param i The value
|
||||
/// @param s The remaining characters
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_int64( int64_t i, string_view s, error_code& ec );
|
||||
|
||||
/// Called when an unsigend integer is parsed.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param u The value
|
||||
/// @param s The remaining characters
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_uint64( uint64_t u, string_view s, error_code& ec );
|
||||
|
||||
/// Called when a double is parsed.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param d The value
|
||||
/// @param s The remaining characters
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_double( double d, string_view s, error_code& ec );
|
||||
|
||||
/// Called when a boolean is parsed.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param b The value
|
||||
/// @param s The remaining characters
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_bool( bool b, error_code& ec );
|
||||
|
||||
/// Called when a null is parsed.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_null( error_code& ec );
|
||||
|
||||
/// Called with characters corresponding to part of the current comment.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param s The partial characters.
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_comment_part( string_view s, error_code& ec );
|
||||
|
||||
/// Called with the last characters corresponding to the current comment.
|
||||
///
|
||||
/// @return `true` on success.
|
||||
/// @param s The remaining characters
|
||||
/// @param ec Set to the error, if any occurred.
|
||||
///
|
||||
bool on_comment( string_view s, error_code& ec );
|
||||
};
|
||||
@endcode
|
||||
|
||||
@see
|
||||
@ref parse,
|
||||
@ref stream_parser,
|
||||
[Validating parser example](../../doc/html/json/examples.html#json.examples.validate).
|
||||
|
||||
@headerfile <boost/json/basic_parser.hpp>
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
template< bool StackEmpty_, char First_ >
|
||||
struct parse_number_helper;
|
||||
|
||||
// optimization: must come first
|
||||
Handler h_;
|
||||
|
||||
number num_;
|
||||
error_code ec_;
|
||||
detail::stack st_;
|
||||
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
|
||||
|
||||
template<bool StackEmpty_/*, bool Terminal_*/>
|
||||
const char* parse_comment(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
/*std::integral_constant<bool, Terminal_>*/ bool terminal);
|
||||
|
||||
template<bool StackEmpty_>
|
||||
const char* parse_document(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty);
|
||||
|
||||
template<bool StackEmpty_, bool AllowComments_/*,
|
||||
bool AllowTrailing_, bool AllowBadUTF8_*/>
|
||||
const char* parse_value(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
std::integral_constant<bool, AllowComments_> allow_comments,
|
||||
/*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
|
||||
/*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8);
|
||||
|
||||
template<bool AllowComments_/*,
|
||||
bool AllowTrailing_, bool AllowBadUTF8_*/>
|
||||
const char* resume_value(const char* p,
|
||||
std::integral_constant<bool, AllowComments_> allow_comments,
|
||||
/*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
|
||||
/*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8);
|
||||
|
||||
template<bool StackEmpty_, bool AllowComments_/*,
|
||||
bool AllowTrailing_, bool AllowBadUTF8_*/>
|
||||
const char* parse_object(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
std::integral_constant<bool, AllowComments_> allow_comments,
|
||||
/*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
|
||||
/*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8);
|
||||
|
||||
template<bool StackEmpty_, bool AllowComments_/*,
|
||||
bool AllowTrailing_, bool AllowBadUTF8_*/>
|
||||
const char* parse_array(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
std::integral_constant<bool, AllowComments_> allow_comments,
|
||||
/*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
|
||||
/*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8);
|
||||
|
||||
template<int Literal>
|
||||
const char* parse_literal(const char* p,
|
||||
std::integral_constant<int, Literal> literal);
|
||||
|
||||
template<bool StackEmpty_, bool IsKey_/*,
|
||||
bool AllowBadUTF8_*/>
|
||||
const char* parse_string(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
std::integral_constant<bool, IsKey_> is_key,
|
||||
/*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8);
|
||||
|
||||
template<bool StackEmpty_, char First_, number_precision Numbers_>
|
||||
const char* parse_number(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
std::integral_constant<char, First_> first,
|
||||
std::integral_constant<number_precision, Numbers_> numbers);
|
||||
|
||||
template<bool StackEmpty_, bool IsKey_/*,
|
||||
bool AllowBadUTF8_*/>
|
||||
const char* parse_unescaped(const char* p,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
std::integral_constant<bool, IsKey_> is_key,
|
||||
/*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8);
|
||||
|
||||
template<bool StackEmpty_/*, bool IsKey_,
|
||||
bool AllowBadUTF8_*/>
|
||||
const char* parse_escaped(
|
||||
const char* p,
|
||||
std::size_t total,
|
||||
std::integral_constant<bool, StackEmpty_> stack_empty,
|
||||
/*std::integral_constant<bool, IsKey_>*/ bool is_key,
|
||||
/*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8);
|
||||
|
||||
// intentionally private
|
||||
std::size_t
|
||||
depth() const noexcept
|
||||
{
|
||||
return opt_.max_depth - depth_;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Copy constructor (deleted)
|
||||
basic_parser(
|
||||
basic_parser const&) = delete;
|
||||
|
||||
/// Copy assignment (deleted)
|
||||
basic_parser& operator=(
|
||||
basic_parser const&) = delete;
|
||||
|
||||
/** Destructor.
|
||||
|
||||
All dynamically allocated internal memory is freed.
|
||||
|
||||
@par Effects
|
||||
@code
|
||||
this->handler().~Handler()
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Same as `~Handler()`.
|
||||
|
||||
@par Exception Safety
|
||||
Same as `~Handler()`.
|
||||
*/
|
||||
~basic_parser() = default;
|
||||
|
||||
/** Constructor.
|
||||
|
||||
This function constructs the parser with
|
||||
the specified options, with any additional
|
||||
arguments forwarded to the handler's constructor.
|
||||
|
||||
@par Complexity
|
||||
Same as `Handler( std::forward< Args >( args )... )`.
|
||||
|
||||
@par Exception Safety
|
||||
Same as `Handler( std::forward< Args >( args )... )`.
|
||||
|
||||
@param opt Configuration settings for the parser.
|
||||
If this structure is default constructed, the
|
||||
parser will accept only standard JSON.
|
||||
|
||||
@param args Optional additional arguments
|
||||
forwarded to the handler's constructor.
|
||||
|
||||
@see parse_options
|
||||
*/
|
||||
template<class... Args>
|
||||
explicit
|
||||
basic_parser(
|
||||
parse_options const& opt,
|
||||
Args&&... args);
|
||||
|
||||
/** Return a reference to the handler.
|
||||
|
||||
This function provides access to the constructed
|
||||
instance of the handler owned by the parser.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
Handler&
|
||||
handler() noexcept
|
||||
{
|
||||
return h_;
|
||||
}
|
||||
|
||||
/** Return a reference to the handler.
|
||||
|
||||
This function provides access to the constructed
|
||||
instance of the handler owned by the parser.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
Handler const&
|
||||
handler() const noexcept
|
||||
{
|
||||
return h_;
|
||||
}
|
||||
|
||||
/** Return the last error.
|
||||
|
||||
This returns the last error code which
|
||||
was generated in the most recent call
|
||||
to @ref write_some.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
error_code
|
||||
last_error() const noexcept
|
||||
{
|
||||
return ec_;
|
||||
}
|
||||
|
||||
/** Return true if a complete JSON has been parsed.
|
||||
|
||||
This function returns `true` when all of these
|
||||
conditions are met:
|
||||
|
||||
@li A complete serialized JSON has been
|
||||
presented to the parser, and
|
||||
|
||||
@li No error or exception has occurred since the
|
||||
parser was constructed, or since the last call
|
||||
to @ref reset,
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
bool
|
||||
done() const noexcept
|
||||
{
|
||||
return done_;
|
||||
}
|
||||
|
||||
/** Reset the state, to parse a new document.
|
||||
|
||||
This function discards the current parsing
|
||||
state, to prepare for parsing a new document.
|
||||
Dynamically allocated temporary memory used
|
||||
by the implementation is not deallocated.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
void
|
||||
reset() noexcept;
|
||||
|
||||
/** Indicate a parsing failure.
|
||||
|
||||
This changes the state of the parser to indicate
|
||||
that the parse has failed. A parser implementation
|
||||
can use this to fail the parser if needed due to
|
||||
external inputs.
|
||||
|
||||
@note
|
||||
|
||||
If `!ec`, the stored error code is unspecified.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param ec The error code to set. If the code does
|
||||
not indicate failure, an implementation-defined
|
||||
error code that indicates failure will be stored
|
||||
instead.
|
||||
*/
|
||||
void
|
||||
fail(error_code ec) noexcept;
|
||||
|
||||
/** Parse some of an input string as JSON, incrementally.
|
||||
|
||||
This function parses the JSON in the specified
|
||||
buffer, calling the handler to emit each SAX
|
||||
parsing event. The parse proceeds from the
|
||||
current state, which is at the beginning of a
|
||||
new JSON or in the middle of the current JSON
|
||||
if any characters were already parsed.
|
||||
\n
|
||||
The characters in the buffer are processed
|
||||
starting from the beginning, until one of the
|
||||
following conditions is met:
|
||||
|
||||
@li All of the characters in the buffer
|
||||
have been parsed, or
|
||||
|
||||
@li Some of the characters in the buffer
|
||||
have been parsed and the JSON is complete, or
|
||||
|
||||
@li A parsing error occurs.
|
||||
|
||||
The supplied buffer does not need to contain the
|
||||
entire JSON. Subsequent calls can provide more
|
||||
serialized data, allowing JSON to be processed
|
||||
incrementally. The end of the serialized JSON
|
||||
can be indicated by passing `more = false`.
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to the handler may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON.
|
||||
|
||||
@return The number of characters successfully
|
||||
parsed, which may be smaller than `size`.
|
||||
|
||||
@param more `true` if there are possibly more
|
||||
buffers in the current JSON, otherwise `false`.
|
||||
|
||||
@param data A pointer to a buffer of `size`
|
||||
characters to parse.
|
||||
|
||||
@param size The number of characters pointed to
|
||||
by `data`.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
/** @{ */
|
||||
std::size_t
|
||||
write_some(
|
||||
bool more,
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec);
|
||||
|
||||
std::size_t
|
||||
write_some(
|
||||
bool more,
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
std::error_code& ec);
|
||||
/** @} */
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+2947
File diff suppressed because it is too large
Load Diff
+400
@@ -0,0 +1,400 @@
|
||||
//
|
||||
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_CONVERSION_HPP
|
||||
#define BOOST_JSON_CONVERSION_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/fwd.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template< class Ctx, class T, class Dir >
|
||||
struct supported_context;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Customization point tag.
|
||||
|
||||
This tag type is used by the function
|
||||
@ref value_from to select overloads
|
||||
of `tag_invoke`.
|
||||
|
||||
@note This type is empty; it has no members.
|
||||
|
||||
@see @ref value_from, @ref value_to, @ref value_to_tag,
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
|
||||
tag_invoke: A general pattern for supporting customisable functions</a>
|
||||
*/
|
||||
struct value_from_tag { };
|
||||
|
||||
/** Customization point tag type.
|
||||
|
||||
This tag type is used by the function
|
||||
@ref value_to to select overloads
|
||||
of `tag_invoke`.
|
||||
|
||||
@note This type is empty; it has no members.
|
||||
|
||||
@see @ref value_from, @ref value_from_tag, @ref value_to,
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
|
||||
tag_invoke: A general pattern for supporting customisable functions</a>
|
||||
*/
|
||||
template<class T>
|
||||
struct value_to_tag { };
|
||||
|
||||
/** Customization point tag type.
|
||||
|
||||
This tag type is used by the function
|
||||
@ref try_value_to to select overloads
|
||||
of `tag_invoke`.
|
||||
|
||||
@note This type is empty; it has no members.
|
||||
|
||||
@see @ref value_to, @ref value_to_tag
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1895r0.pdf">
|
||||
tag_invoke: A general pattern for supporting customisable functions</a>
|
||||
*/
|
||||
template<class T>
|
||||
struct try_value_to_tag { };
|
||||
|
||||
/** Determine if `T` can be treated like a string during conversions.
|
||||
|
||||
Provides the member constant `value` that is equal to `true`, if `T` is
|
||||
convertible to @ref string_view. Otherwise, `value` is equal to `false`.
|
||||
<br>
|
||||
|
||||
Users can specialize the trait for their own types if they don't want them
|
||||
to be treated like strings. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_string_like<your::string> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
|
||||
@par Types satisfying the trait
|
||||
|
||||
@ref string,
|
||||
@ref string_view,
|
||||
<a href="https://en.cppreference.com/w/cpp/string/basic_string"><tt>std::string</tt></a>,
|
||||
<a href="https://en.cppreference.com/w/cpp/string/basic_string_view"><tt>std::string_view</tt></a>.
|
||||
|
||||
@see @ref value_from, @ref value_to
|
||||
*/
|
||||
template<class T>
|
||||
struct is_string_like;
|
||||
|
||||
/** Determine if `T` can be treated like a sequence during conversions.
|
||||
|
||||
Given `t`, a glvalue of type `T`, if
|
||||
|
||||
@li given `It`, the type denoted by `decltype(std::begin(t))`,
|
||||
<tt>std::iterator_traits<It>::iterator_category</tt> is well-formed and
|
||||
denotes a type; and
|
||||
|
||||
@li `decltype(std::end(t))` also denotes the type `It`;
|
||||
|
||||
then the trait provides the member constant `value` that is equal to
|
||||
`true`. Otherwise, `value` is equal to `false`.<br>
|
||||
|
||||
Users can specialize the trait for their own types if they don't want them
|
||||
to be treated like sequences. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_sequence_like<your::container> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
|
||||
|
||||
@par Types satisfying the trait
|
||||
|
||||
Any <a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
|
||||
array types.
|
||||
|
||||
@see @ref value_from, @ref value_to
|
||||
*/
|
||||
template<class T>
|
||||
struct is_sequence_like;
|
||||
|
||||
/** Determine if `T` can be treated like a 1-to-1 mapping during
|
||||
conversions.
|
||||
|
||||
Given `t`, a glvalue of type `T`, if
|
||||
|
||||
@li <tt>is_sequence_like<T>::value</tt> is `true`; and
|
||||
|
||||
@li given type `It` denoting `decltype(std::begin(t))`, and types `K`
|
||||
and `M`, <tt>std::iterator_traits<It>::value_type</tt> denotes
|
||||
`std::pair<K, M>`; and
|
||||
|
||||
@li <tt>std::is_string_like<K>::value</tt> is `true`; and
|
||||
|
||||
@li given `v`, a glvalue of type `V`, and `E`, the type denoted by
|
||||
`decltype(t.emplace(v))`,
|
||||
<tt>std::is_tuple_like<E>::value</tt> is `true`;
|
||||
|
||||
then the trait provides the member constant `value`
|
||||
that is equal to `true`. Otherwise, `value` is equal to `false`.<br>
|
||||
|
||||
Users can specialize the trait for their own types if they don't want them
|
||||
to be treated like mappings. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_map_like<your::map> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
|
||||
|
||||
@note
|
||||
|
||||
The restriction for `t.emplace()` return type ensures that the container
|
||||
does not accept duplicate keys.
|
||||
|
||||
@par Types satisfying the trait
|
||||
|
||||
<a href="https://en.cppreference.com/w/cpp/container/map"><tt>std::map</tt></a>,
|
||||
<a href="https://en.cppreference.com/w/cpp/container/unordered_map"><tt>std::unordered_map</tt></a>.
|
||||
|
||||
@see @ref value_from, @ref value_to
|
||||
*/
|
||||
template<class T>
|
||||
struct is_map_like;
|
||||
|
||||
/** Determine if `T` can be treated like a tuple during conversions.
|
||||
|
||||
Provides the member constant `value` that is equal to `true`, if
|
||||
<tt>std::tuple_size<T>::value</tt> is a positive number. Otherwise, `value`
|
||||
is equal to `false`.<br>
|
||||
|
||||
Users can specialize the trait for their own types if they don't want them
|
||||
to be treated like tuples. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_tuple_like<your::tuple> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
|
||||
|
||||
@par Types satisfying the trait
|
||||
|
||||
<a href="https://en.cppreference.com/w/cpp/utility/tuple"><tt>std::tuple</tt></a>,
|
||||
<a href="https://en.cppreference.com/w/cpp/utility/pair"><tt>std::pair</tt></a>.
|
||||
|
||||
@see @ref value_from, @ref value_to
|
||||
*/
|
||||
template<class T>
|
||||
struct is_tuple_like;
|
||||
|
||||
/** Determine if `T` can be treated like null during conversions.
|
||||
|
||||
Primary template instantiations provide the member constant `value` that is
|
||||
equal to `false`. Users can specialize the trait for their own types if
|
||||
they **do** want them to be treated as nulls. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_null_like<your::null_type> : std::true_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
|
||||
|
||||
@par Types satisfying the trait
|
||||
|
||||
<a href="https://en.cppreference.com/w/cpp/types/nullptr_t"><tt>std::nullptr_t</tt></a>.
|
||||
|
||||
@see @ref value_from, @ref value_to
|
||||
*/
|
||||
template<class T>
|
||||
struct is_null_like
|
||||
: std::false_type
|
||||
{ };
|
||||
|
||||
/** Determine if `T` should be treated as a described class
|
||||
|
||||
Described classes are serialised as objects with an element for each
|
||||
described public data member. A described class should not have described
|
||||
bases or non-public members.<br>
|
||||
|
||||
Or more formally, given `L`, a class template
|
||||
of the form `template<class...> struct L {};`, if
|
||||
|
||||
@li <tt>boost::describe::has_members<T, boost::describe::mod_public>::value</tt> is `true`; and
|
||||
|
||||
@li `boost::describe::describe_members<T, boost::describe::mod_private | boost::describe::mod_protected>` denotes `L<>`; and
|
||||
|
||||
@li `boost::describe::describe_bases<T, boost::describe::mod_any_access>` denotes `L<>`; and
|
||||
|
||||
@li <tt>std::is_union<T>::value</tt> is `false`;
|
||||
|
||||
then the trait provides the member constant `value`
|
||||
that is equal to `true`. Otherwise, `value` is equal to `false`.<br>
|
||||
|
||||
Users can specialize the trait for their own types if they don't want them
|
||||
to be treated as described classes. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_described_class<your::described_class> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
|
||||
Users can also specialize the trait for their own types _with_ described
|
||||
bases to enable this conversion implementation. In this case the class will
|
||||
be serialized in a flattened way, that is members of bases will be
|
||||
serialized as direct elements of the object, and no nested objects will be
|
||||
created for bases.
|
||||
|
||||
@see <a href="https://www.boost.org/doc/libs/develop/libs/describe/doc/html/describe.html">Boost.Describe</a>.
|
||||
*/
|
||||
template<class T>
|
||||
struct is_described_class;
|
||||
|
||||
/** Determine if `T` should be treated as a described enum
|
||||
|
||||
Described enums are serialised as strings when their value equals to a
|
||||
described enumerator, and as integers otherwise. The reverse operation
|
||||
does not convert numbers to enums values, though, and instead produces
|
||||
an error.<br>
|
||||
|
||||
If <tt>boost::describe::has_describe_enumerators<T>::value</tt> is `true`,
|
||||
then the trait provides the member constant `value`
|
||||
that is equal to `true`. Otherwise, `value` is equal to `false`.<br>
|
||||
|
||||
Users can specialize the trait for their own enums if they don't want them
|
||||
to be treated as described enums. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_described_enum<your::described_enum> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
|
||||
@see <a href="https://www.boost.org/doc/libs/develop/libs/describe/doc/html/describe.html">Boost.Describe</a>.
|
||||
*/
|
||||
template<class T>
|
||||
struct is_described_enum;
|
||||
|
||||
/** Determine if `T` should be treated as a variant
|
||||
|
||||
Variants are serialised the same way their active alternative is
|
||||
serialised. The opposite conversion selects the first alternative for which
|
||||
conversion succeeds.<br>
|
||||
|
||||
Given `t`, a glvalue of type ` const T`, if
|
||||
<tt>t.valueless_by_exception()</tt> is well-formed, then the trait provides
|
||||
the member constant `value` that is equal to `true`. Otherwise, `value` is
|
||||
equal to `false`.<br>
|
||||
|
||||
Users can specialize the trait for their own types if they don't want them
|
||||
to be treated as variants. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_variant_like<your::variant> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
*/
|
||||
template<class T>
|
||||
struct is_variant_like;
|
||||
|
||||
/** Determine if `T` should be treated as an optional
|
||||
|
||||
Optionals are serialised as `null` if empty, or as the stored type
|
||||
otherwise.<br>
|
||||
|
||||
Given `t`, a glvalue of type `T`, if
|
||||
|
||||
@li <tt>decltype( t.value() )</tt> is well-formed and isn't a void type; and
|
||||
|
||||
@li <tt>t.reset()</tt> is well-formed;
|
||||
|
||||
then the trait provides the member constant `value`
|
||||
that is equal to `true`. Otherwise, `value` is equal to `false`.<br>
|
||||
|
||||
Users can specialize the trait for their own types if they don't want them
|
||||
to be treated as optionals. For example:
|
||||
|
||||
@code
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template <>
|
||||
struct is_optional_like<your::optional> : std::false_type
|
||||
{ };
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
@endcode
|
||||
*/
|
||||
template<class T>
|
||||
struct is_optional_like;
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/json/impl/conversion.hpp>
|
||||
|
||||
#endif // BOOST_JSON_CONVERSION_HPP
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_ARRAY_HPP
|
||||
#define BOOST_JSON_DETAIL_ARRAY_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
class value;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class unchecked_array
|
||||
{
|
||||
value* data_;
|
||||
std::size_t size_;
|
||||
storage_ptr const& sp_;
|
||||
|
||||
public:
|
||||
inline
|
||||
~unchecked_array();
|
||||
|
||||
unchecked_array(
|
||||
value* data,
|
||||
std::size_t size,
|
||||
storage_ptr const& sp) noexcept
|
||||
: data_(data)
|
||||
, size_(size)
|
||||
, sp_(sp)
|
||||
{
|
||||
}
|
||||
|
||||
unchecked_array(
|
||||
unchecked_array&& other) noexcept
|
||||
: data_(other.data_)
|
||||
, size_(other.size_)
|
||||
, sp_(other.sp_)
|
||||
{
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
|
||||
storage_ptr const&
|
||||
storage() const noexcept
|
||||
{
|
||||
return sp_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
relocate(value* dest) noexcept;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
// includes are at the bottom of <boost/json/value.hpp>
|
||||
|
||||
#endif
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_BUFFER_HPP
|
||||
#define BOOST_JSON_DETAIL_BUFFER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/string_view.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
// A simple string-like temporary static buffer
|
||||
template<std::size_t N>
|
||||
class buffer
|
||||
{
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
|
||||
buffer() = default;
|
||||
|
||||
bool
|
||||
empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
string_view
|
||||
get() const noexcept
|
||||
{
|
||||
return {buf_, size_};
|
||||
}
|
||||
|
||||
operator string_view() const noexcept
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
char const*
|
||||
data() const noexcept
|
||||
{
|
||||
return buf_;
|
||||
}
|
||||
|
||||
size_type
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
size_type
|
||||
capacity() const noexcept
|
||||
{
|
||||
return N - size_;
|
||||
}
|
||||
|
||||
size_type
|
||||
max_size() const noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
void
|
||||
clear() noexcept
|
||||
{
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
push_back(char ch) noexcept
|
||||
{
|
||||
BOOST_ASSERT(capacity() > 0);
|
||||
buf_[size_++] = ch;
|
||||
}
|
||||
|
||||
// append an unescaped string
|
||||
void
|
||||
append(
|
||||
char const* s,
|
||||
size_type n)
|
||||
{
|
||||
BOOST_ASSERT(n <= N - size_);
|
||||
std::memcpy(buf_ + size_, s, n);
|
||||
size_ += n;
|
||||
}
|
||||
|
||||
// append valid 32-bit code point as utf8
|
||||
void
|
||||
append_utf8(
|
||||
unsigned long cp) noexcept
|
||||
{
|
||||
auto dest = buf_ + size_;
|
||||
if(cp < 0x80)
|
||||
{
|
||||
BOOST_ASSERT(size_ <= N - 1);
|
||||
dest[0] = static_cast<char>(cp);
|
||||
size_ += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(cp < 0x800)
|
||||
{
|
||||
BOOST_ASSERT(size_ <= N - 2);
|
||||
dest[0] = static_cast<char>( (cp >> 6) | 0xc0);
|
||||
dest[1] = static_cast<char>( (cp & 0x3f) | 0x80);
|
||||
size_ += 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if(cp < 0x10000)
|
||||
{
|
||||
BOOST_ASSERT(size_ <= N - 3);
|
||||
dest[0] = static_cast<char>( (cp >> 12) | 0xe0);
|
||||
dest[1] = static_cast<char>(((cp >> 6) & 0x3f) | 0x80);
|
||||
dest[2] = static_cast<char>( (cp & 0x3f) | 0x80);
|
||||
size_ += 3;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_ASSERT(size_ <= N - 4);
|
||||
dest[0] = static_cast<char>( (cp >> 18) | 0xf0);
|
||||
dest[1] = static_cast<char>(((cp >> 12) & 0x3f) | 0x80);
|
||||
dest[2] = static_cast<char>(((cp >> 6) & 0x3f) | 0x80);
|
||||
dest[3] = static_cast<char>( (cp & 0x3f) | 0x80);
|
||||
size_ += 4;
|
||||
}
|
||||
}
|
||||
private:
|
||||
char buf_[N];
|
||||
size_type size_ = 0;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_CHARS_FORMAT_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_CHARS_FORMAT_HPP
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv {
|
||||
|
||||
// Floating-point format for primitive numerical conversion
|
||||
// chars_format is a bitmask type (16.3.3.3.3)
|
||||
enum class chars_format : unsigned
|
||||
{
|
||||
scientific = 1 << 0,
|
||||
fixed = 1 << 1,
|
||||
hex = 1 << 2,
|
||||
general = fixed | scientific
|
||||
};
|
||||
|
||||
}}}} // Namespaces
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_CHARS_FORMAT_HPP
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <boost/json/detail/charconv/detail/significand_tables.hpp>
|
||||
#include <boost/json/detail/charconv/detail/emulated128.hpp>
|
||||
#include <boost/core/bit.hpp>
|
||||
#include <cstdint>
|
||||
#include <cfloat>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
|
||||
|
||||
static constexpr double powers_of_ten[] = {
|
||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
|
||||
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
|
||||
};
|
||||
|
||||
// Attempts to compute i * 10^(power) exactly; and if "negative" is true, negate the result.
|
||||
//
|
||||
// This function will only work in some cases, when it does not work, success is
|
||||
// set to false. This should work *most of the time* (like 99% of the time).
|
||||
// We assume that power is in the [-325, 308] interval.
|
||||
inline double compute_float64(std::int64_t power, std::uint64_t i, bool negative, bool& success) noexcept
|
||||
{
|
||||
static constexpr auto smallest_power = -325;
|
||||
static constexpr auto largest_power = 308;
|
||||
|
||||
// We start with a fast path
|
||||
// It was described in Clinger WD.
|
||||
// How to read floating point numbers accurately.
|
||||
// ACM SIGPLAN Notices. 1990
|
||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||
if (0 <= power && power <= 22 && i <= UINT64_C(9007199254740991))
|
||||
#else
|
||||
if (-22 <= power && power <= 22 && i <= UINT64_C(9007199254740991))
|
||||
#endif
|
||||
{
|
||||
// The general idea is as follows.
|
||||
// If 0 <= s < 2^53 and if 10^0 <= p <= 10^22 then
|
||||
// 1) Both s and p can be represented exactly as 64-bit floating-point
|
||||
// values
|
||||
// (binary64).
|
||||
// 2) Because s and p can be represented exactly as floating-point values,
|
||||
// then s * p
|
||||
// and s / p will produce correctly rounded values.
|
||||
|
||||
auto d = static_cast<double>(i);
|
||||
|
||||
if (power < 0)
|
||||
{
|
||||
d = d / powers_of_ten[-power];
|
||||
}
|
||||
else
|
||||
{
|
||||
d = d * powers_of_ten[power];
|
||||
}
|
||||
|
||||
if (negative)
|
||||
{
|
||||
d = -d;
|
||||
}
|
||||
|
||||
success = true;
|
||||
return d;
|
||||
}
|
||||
|
||||
// When 22 < power && power < 22 + 16, we could
|
||||
// hope for another, secondary fast path. It was
|
||||
// described by David M. Gay in "Correctly rounded
|
||||
// binary-decimal and decimal-binary conversions." (1990)
|
||||
// If you need to compute i * 10^(22 + x) for x < 16,
|
||||
// first compute i * 10^x, if you know that result is exact
|
||||
// (e.g., when i * 10^x < 2^53),
|
||||
// then you can still proceed and do (i * 10^x) * 10^22.
|
||||
// Is this worth your time?
|
||||
// You need 22 < power *and* power < 22 + 16 *and* (i * 10^(x-22) < 2^53)
|
||||
// for this second fast path to work.
|
||||
// If you have 22 < power *and* power < 22 + 16, and then you
|
||||
// optimistically compute "i * 10^(x-22)", there is still a chance that you
|
||||
// have wasted your time if i * 10^(x-22) >= 2^53. It makes the use cases of
|
||||
// this optimization maybe less common than we would like. Source:
|
||||
// http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
// also used in RapidJSON: https://rapidjson.org/strtod_8h_source.html
|
||||
|
||||
if (i == 0 || power < smallest_power)
|
||||
{
|
||||
return negative ? -0.0 : 0.0;
|
||||
}
|
||||
else if (power > largest_power)
|
||||
{
|
||||
return negative ? -HUGE_VAL : HUGE_VAL;
|
||||
}
|
||||
|
||||
const std::uint64_t factor_significand = significand_64[power - smallest_power];
|
||||
const std::int64_t exponent = (((152170 + 65536) * power) >> 16) + 1024 + 63;
|
||||
int leading_zeros = boost::core::countl_zero(i);
|
||||
i <<= static_cast<std::uint64_t>(leading_zeros);
|
||||
|
||||
uint128 product = umul128(i, factor_significand);
|
||||
std::uint64_t low = product.low;
|
||||
std::uint64_t high = product.high;
|
||||
|
||||
// We know that upper has at most one leading zero because
|
||||
// both i and factor_mantissa have a leading one. This means
|
||||
// that the result is at least as large as ((1<<63)*(1<<63))/(1<<64).
|
||||
//
|
||||
// As long as the first 9 bits of "upper" are not "1", then we
|
||||
// know that we have an exact computed value for the leading
|
||||
// 55 bits because any imprecision would play out as a +1, in the worst case.
|
||||
// Having 55 bits is necessary because we need 53 bits for the mantissa,
|
||||
// but we have to have one rounding bit and, we can waste a bit if the most
|
||||
// significant bit of the product is zero.
|
||||
//
|
||||
// We expect this next branch to be rarely taken (say 1% of the time).
|
||||
// When (upper & 0x1FF) == 0x1FF, it can be common for
|
||||
// lower + i < lower to be true (proba. much higher than 1%).
|
||||
if (BOOST_UNLIKELY((high & 0x1FF) == 0x1FF) && (low + i < low))
|
||||
{
|
||||
const std::uint64_t factor_significand_low = significand_128[power - smallest_power];
|
||||
product = umul128(i, factor_significand_low);
|
||||
//const std::uint64_t product_low = product.low;
|
||||
const std::uint64_t product_middle2 = product.high;
|
||||
const std::uint64_t product_middle1 = low;
|
||||
std::uint64_t product_high = high;
|
||||
const std::uint64_t product_middle = product_middle1 + product_middle2;
|
||||
|
||||
if (product_middle < product_middle1)
|
||||
{
|
||||
product_high++;
|
||||
}
|
||||
|
||||
// Commented out because possibly unneeded
|
||||
// See: https://arxiv.org/pdf/2212.06644.pdf
|
||||
/*
|
||||
// we want to check whether mantissa *i + i would affect our result
|
||||
// This does happen, e.g. with 7.3177701707893310e+15
|
||||
if (((product_middle + 1 == 0) && ((product_high & 0x1FF) == 0x1FF) && (product_low + i < product_low)))
|
||||
{
|
||||
success = false;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
low = product_middle;
|
||||
high = product_high;
|
||||
}
|
||||
|
||||
// The final significand should be 53 bits with a leading 1
|
||||
// We shift it so that it occupies 54 bits with a leading 1
|
||||
const std::uint64_t upper_bit = high >> 63;
|
||||
std::uint64_t significand = high >> (upper_bit + 9);
|
||||
leading_zeros += static_cast<int>(1 ^ upper_bit);
|
||||
|
||||
// If we have lots of trailing zeros we may fall between two values
|
||||
if (BOOST_UNLIKELY((low == 0) && ((high & 0x1FF) == 0) && ((significand & 3) == 1)))
|
||||
{
|
||||
// if significand & 1 == 1 we might need to round up
|
||||
success = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
significand += significand & 1;
|
||||
significand >>= 1;
|
||||
|
||||
// Here the significand < (1<<53), unless there is an overflow
|
||||
if (significand >= (UINT64_C(1) << 53))
|
||||
{
|
||||
significand = (UINT64_C(1) << 52);
|
||||
leading_zeros--;
|
||||
}
|
||||
|
||||
significand &= ~(UINT64_C(1) << 52);
|
||||
const std::uint64_t real_exponent = exponent - leading_zeros;
|
||||
|
||||
// We have to check that real_exponent is in range, otherwise fail
|
||||
if (BOOST_UNLIKELY((real_exponent < 1) || (real_exponent > 2046)))
|
||||
{
|
||||
success = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
significand |= real_exponent << 52;
|
||||
significand |= ((static_cast<std::uint64_t>(negative) << 63));
|
||||
|
||||
double d;
|
||||
std::memcpy(&d, &significand, sizeof(d));
|
||||
|
||||
success = true;
|
||||
return d;
|
||||
}
|
||||
|
||||
}}}}} // Namespaces
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_CONFIG_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <type_traits>
|
||||
#include <cfloat>
|
||||
|
||||
// Use 128 bit integers and supress warnings for using extensions
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
# define BOOST_JSON_INT128_MAX (boost::int128_type)(((boost::uint128_type) 1 << 127) - 1)
|
||||
# define BOOST_JSON_UINT128_MAX ((2 * (boost::uint128_type) BOOST_JSON_INT128_MAX) + 1)
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_CXX14_CONSTEXPR
|
||||
# define BOOST_JSON_CXX14_CONSTEXPR BOOST_CXX14_CONSTEXPR
|
||||
# define BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE BOOST_CXX14_CONSTEXPR
|
||||
#else
|
||||
# define BOOST_JSON_CXX14_CONSTEXPR inline
|
||||
# define BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 5
|
||||
# define BOOST_JSON_GCC5_CONSTEXPR inline
|
||||
#else
|
||||
# define BOOST_JSON_GCC5_CONSTEXPR BOOST_JSON_CXX14_CONSTEXPR
|
||||
#endif
|
||||
|
||||
// Inclue intrinsics if available
|
||||
#if defined(BOOST_MSVC)
|
||||
# include <intrin.h>
|
||||
# if defined(_WIN64)
|
||||
# define BOOST_JSON_HAS_MSVC_64BIT_INTRINSICS
|
||||
# else
|
||||
# define BOOST_JSON_HAS_MSVC_32BIT_INTRINSICS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Suppress additional buffer overrun check.
|
||||
// I have no idea why MSVC thinks some functions here are vulnerable to the buffer overrun
|
||||
// attacks. No, they aren't.
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define BOOST_JSON_SAFEBUFFERS
|
||||
#elif defined(_MSC_VER)
|
||||
#define BOOST_JSON_SAFEBUFFERS __declspec(safebuffers)
|
||||
#else
|
||||
#define BOOST_JSON_SAFEBUFFERS
|
||||
#endif
|
||||
|
||||
#if defined(__has_builtin)
|
||||
#define BOOST_JSON_HAS_BUILTIN(x) __has_builtin(x)
|
||||
#else
|
||||
#define BOOST_JSON_HAS_BUILTIN(x) false
|
||||
#endif
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_CONFIG_HPP
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// If the architecture (e.g. ARM) does not have __int128 we need to emulate it
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_EMULATED128_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_EMULATED128_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
|
||||
|
||||
// Compilers might support built-in 128-bit integer types. However, it seems that
|
||||
// emulating them with a pair of 64-bit integers actually produces a better code,
|
||||
// so we avoid using those built-ins. That said, they are still useful for
|
||||
// implementing 64-bit x 64-bit -> 128-bit multiplication.
|
||||
|
||||
struct uint128
|
||||
{
|
||||
std::uint64_t high;
|
||||
std::uint64_t low;
|
||||
|
||||
uint128& operator+=(std::uint64_t n) & noexcept
|
||||
{
|
||||
#if BOOST_JSON_HAS_BUILTIN(__builtin_addcll)
|
||||
|
||||
unsigned long long carry;
|
||||
low = __builtin_addcll(low, n, 0, &carry);
|
||||
high = __builtin_addcll(high, 0, carry, &carry);
|
||||
|
||||
#elif BOOST_JSON_HAS_BUILTIN(__builtin_ia32_addcarryx_u64)
|
||||
|
||||
unsigned long long result;
|
||||
auto carry = __builtin_ia32_addcarryx_u64(0, low, n, &result);
|
||||
low = result;
|
||||
__builtin_ia32_addcarryx_u64(carry, high, 0, &result);
|
||||
high = result;
|
||||
|
||||
#elif defined(BOOST_MSVC) && defined(_M_X64)
|
||||
|
||||
auto carry = _addcarry_u64(0, low, n, &low);
|
||||
_addcarry_u64(carry, high, 0, &high);
|
||||
|
||||
#else
|
||||
|
||||
auto sum = low + n;
|
||||
high += (sum < low ? 1 : 0);
|
||||
low = sum;
|
||||
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
static inline std::uint64_t umul64(std::uint32_t x, std::uint32_t y) noexcept
|
||||
{
|
||||
#if defined(BOOST_JSON_HAS_MSVC_32BIT_INTRINSICS) && !defined(_M_ARM)
|
||||
|
||||
return __emulu(x, y);
|
||||
|
||||
#else
|
||||
|
||||
return x * static_cast<std::uint64_t>(y);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get 128-bit result of multiplication of two 64-bit unsigned integers.
|
||||
BOOST_JSON_SAFEBUFFERS inline uint128 umul128(std::uint64_t x, std::uint64_t y) noexcept
|
||||
{
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
|
||||
auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y);
|
||||
return {static_cast<std::uint64_t>(result >> 64), static_cast<std::uint64_t>(result)};
|
||||
|
||||
#elif defined(BOOST_JSON_HAS_MSVC_64BIT_INTRINSICS) && !defined(_M_ARM64)
|
||||
|
||||
std::uint64_t high;
|
||||
std::uint64_t low = _umul128(x, y, &high);
|
||||
return {high, low};
|
||||
|
||||
// https://developer.arm.com/documentation/dui0802/a/A64-General-Instructions/UMULH
|
||||
#elif defined(_M_ARM64) && !defined(__MINGW32__)
|
||||
|
||||
std::uint64_t high = __umulh(x, y);
|
||||
std::uint64_t low = x * y;
|
||||
return {high, low};
|
||||
|
||||
#else
|
||||
|
||||
auto a = static_cast<std::uint32_t>(x >> 32);
|
||||
auto b = static_cast<std::uint32_t>(x);
|
||||
auto c = static_cast<std::uint32_t>(y >> 32);
|
||||
auto d = static_cast<std::uint32_t>(y);
|
||||
|
||||
auto ac = umul64(a, c);
|
||||
auto bc = umul64(b, c);
|
||||
auto ad = umul64(a, d);
|
||||
auto bd = umul64(b, d);
|
||||
|
||||
auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc);
|
||||
|
||||
return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
|
||||
(intermediate << 32) + static_cast<std::uint32_t>(bd)};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_JSON_SAFEBUFFERS inline std::uint64_t umul128_upper64(std::uint64_t x, std::uint64_t y) noexcept
|
||||
{
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
|
||||
auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y);
|
||||
return static_cast<std::uint64_t>(result >> 64);
|
||||
|
||||
#elif defined(BOOST_JSON_HAS_MSVC_64BIT_INTRINSICS)
|
||||
|
||||
return __umulh(x, y);
|
||||
|
||||
#else
|
||||
|
||||
auto a = static_cast<std::uint32_t>(x >> 32);
|
||||
auto b = static_cast<std::uint32_t>(x);
|
||||
auto c = static_cast<std::uint32_t>(y >> 32);
|
||||
auto d = static_cast<std::uint32_t>(y);
|
||||
|
||||
auto ac = umul64(a, c);
|
||||
auto bc = umul64(b, c);
|
||||
auto ad = umul64(a, d);
|
||||
auto bd = umul64(b, d);
|
||||
|
||||
auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc);
|
||||
|
||||
return ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get upper 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit
|
||||
// unsigned integer.
|
||||
BOOST_JSON_SAFEBUFFERS inline uint128 umul192_upper128(std::uint64_t x, uint128 y) noexcept
|
||||
{
|
||||
auto r = umul128(x, y.high);
|
||||
r += umul128_upper64(x, y.low);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Get upper 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit
|
||||
// unsigned integer.
|
||||
inline std::uint64_t umul96_upper64(std::uint32_t x, std::uint64_t y) noexcept
|
||||
{
|
||||
#if defined(BOOST_HAS_INT128) || defined(BOOST_JSON_HAS_MSVC_64BIT_INTRINSICS)
|
||||
|
||||
return umul128_upper64(static_cast<std::uint64_t>(x) << 32, y);
|
||||
|
||||
#else
|
||||
|
||||
auto yh = static_cast<std::uint32_t>(y >> 32);
|
||||
auto yl = static_cast<std::uint32_t>(y);
|
||||
|
||||
auto xyh = umul64(x, yh);
|
||||
auto xyl = umul64(x, yl);
|
||||
|
||||
return xyh + (xyl >> 32);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get lower 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit
|
||||
// unsigned integer.
|
||||
BOOST_JSON_SAFEBUFFERS inline uint128 umul192_lower128(std::uint64_t x, uint128 y) noexcept
|
||||
{
|
||||
auto high = x * y.high;
|
||||
auto highlow = umul128(x, y.low);
|
||||
return {high + highlow.high, highlow.low};
|
||||
}
|
||||
|
||||
// Get lower 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit
|
||||
// unsigned integer.
|
||||
inline std::uint64_t umul96_lower64(std::uint32_t x, std::uint64_t y) noexcept
|
||||
{
|
||||
return x * y;
|
||||
}
|
||||
|
||||
}}}}} // Namespaces
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_EMULATED128_HPP
|
||||
Vendored
Executable
+283
@@ -0,0 +1,283 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
// Next function can be micro-optimized, but compilers are entirely
|
||||
// able to optimize it well.
|
||||
template <typename UC>
|
||||
BOOST_FORCEINLINE constexpr bool is_integer(UC c) noexcept {
|
||||
return !(c > UC('9') || c < UC('0'));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE constexpr uint64_t byteswap(uint64_t val) {
|
||||
return (val & 0xFF00000000000000) >> 56
|
||||
| (val & 0x00FF000000000000) >> 40
|
||||
| (val & 0x0000FF0000000000) >> 24
|
||||
| (val & 0x000000FF00000000) >> 8
|
||||
| (val & 0x00000000FF000000) << 8
|
||||
| (val & 0x0000000000FF0000) << 24
|
||||
| (val & 0x000000000000FF00) << 40
|
||||
| (val & 0x00000000000000FF) << 56;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
uint64_t read_u64(const char *chars) {
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
uint64_t val = 0;
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
val |= uint64_t(*chars) << (i*8);
|
||||
++chars;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
uint64_t val;
|
||||
::memcpy(&val, chars, sizeof(uint64_t));
|
||||
#ifdef BOOST_JSON_BIG_ENDIAN
|
||||
// Need to read as-if the number was in little-endian order.
|
||||
val = byteswap(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void write_u64(uint8_t *chars, uint64_t val) {
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
*chars = uint8_t(val);
|
||||
val >>= 8;
|
||||
++chars;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#ifdef BOOST_JSON_BIG_ENDIAN
|
||||
// Need to read as-if the number was in little-endian order.
|
||||
val = byteswap(val);
|
||||
#endif
|
||||
::memcpy(chars, &val, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
// credit @aqrit
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
||||
constexpr uint64_t mask = 0x000000FF000000FF;
|
||||
constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
|
||||
constexpr uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
|
||||
val -= 0x3030303030303030;
|
||||
val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
|
||||
val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
|
||||
return uint32_t(val);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE constexpr
|
||||
uint32_t parse_eight_digits_unrolled(const char16_t *) noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE constexpr
|
||||
uint32_t parse_eight_digits_unrolled(const char32_t *) noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
||||
return parse_eight_digits_unrolled(read_u64(chars));
|
||||
}
|
||||
|
||||
// credit @aqrit
|
||||
BOOST_FORCEINLINE constexpr bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
||||
return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) & 0x8080808080808080));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE constexpr
|
||||
bool is_made_of_eight_digits_fast(const char16_t *) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE constexpr
|
||||
bool is_made_of_eight_digits_fast(const char32_t *) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
||||
return is_made_of_eight_digits_fast(read_u64(chars));
|
||||
}
|
||||
|
||||
template <typename UC>
|
||||
struct parsed_number_string_t {
|
||||
int64_t exponent{0};
|
||||
uint64_t mantissa{0};
|
||||
UC const * lastmatch{nullptr};
|
||||
bool negative{false};
|
||||
bool valid{false};
|
||||
bool too_many_digits{false};
|
||||
// contains the range of the significant digits
|
||||
span<const UC> integer{}; // non-nullable
|
||||
span<const UC> fraction{}; // nullable
|
||||
};
|
||||
using byte_span = span<char>;
|
||||
using parsed_number_string = parsed_number_string_t<char>;
|
||||
// Assuming that you use no more than 19 digits, this will
|
||||
// parse an ASCII string.
|
||||
template <typename UC>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept {
|
||||
chars_format const fmt = options.format;
|
||||
UC const decimal_point = options.decimal_point;
|
||||
|
||||
parsed_number_string_t<UC> answer;
|
||||
answer.valid = false;
|
||||
answer.too_many_digits = false;
|
||||
answer.negative = (*p == UC('-'));
|
||||
if (*p == UC('-')) // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
{
|
||||
++p;
|
||||
if (p == pend) {
|
||||
return answer;
|
||||
}
|
||||
if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
UC const * const start_digits = p;
|
||||
|
||||
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
||||
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
||||
// multiplication
|
||||
i = 10 * i +
|
||||
uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later
|
||||
++p;
|
||||
}
|
||||
UC const * const end_of_integer_part = p;
|
||||
int64_t digit_count = int64_t(end_of_integer_part - start_digits);
|
||||
answer.integer = span<const UC>(start_digits, size_t(digit_count));
|
||||
int64_t exponent = 0;
|
||||
if ((p != pend) && (*p == decimal_point)) {
|
||||
++p;
|
||||
UC const * before = p;
|
||||
// can occur at most twice without overflowing, but let it occur more, since
|
||||
// for integers with many digits, digit parsing is the primary bottleneck.
|
||||
if (std::is_same<UC,char>::value) {
|
||||
while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - UC('0'));
|
||||
++p;
|
||||
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
|
||||
}
|
||||
exponent = before - p;
|
||||
answer.fraction = span<const UC>(before, size_t(p - before));
|
||||
digit_count -= exponent;
|
||||
}
|
||||
// we must have encountered at least one integer!
|
||||
if (digit_count == 0) {
|
||||
return answer;
|
||||
}
|
||||
int64_t exp_number = 0; // explicit exponential part
|
||||
if (((unsigned)fmt & (unsigned)chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) {
|
||||
UC const * location_of_e = p;
|
||||
++p;
|
||||
bool neg_exp = false;
|
||||
if ((p != pend) && (UC('-') == *p)) {
|
||||
neg_exp = true;
|
||||
++p;
|
||||
} else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
||||
++p;
|
||||
}
|
||||
if ((p == pend) || !is_integer(*p)) {
|
||||
if(!((unsigned)fmt & (unsigned)chars_format::fixed)) {
|
||||
// We are in error.
|
||||
return answer;
|
||||
}
|
||||
// Otherwise, we will be ignoring the 'e'.
|
||||
p = location_of_e;
|
||||
} else {
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - UC('0'));
|
||||
if (exp_number < 0x10000000) {
|
||||
exp_number = 10 * exp_number + digit;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
if(neg_exp) { exp_number = - exp_number; }
|
||||
exponent += exp_number;
|
||||
}
|
||||
} else {
|
||||
// If it scientific and not fixed, we have to bail out.
|
||||
if(((unsigned)fmt & (unsigned)chars_format::scientific) && !((unsigned)fmt & (unsigned)chars_format::fixed))
|
||||
{
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
answer.lastmatch = p;
|
||||
answer.valid = true;
|
||||
|
||||
// If we frequently had to deal with long strings of digits,
|
||||
// we could extend our code by using a 128-bit integer instead
|
||||
// of a 64-bit integer. However, this is uncommon.
|
||||
//
|
||||
// We can deal with up to 19 digits.
|
||||
if (digit_count > 19) { // this is uncommon
|
||||
// It is possible that the integer had an overflow.
|
||||
// We have to handle the case where we have 0.0000somenumber.
|
||||
// We need to be mindful of the case where we only have zeroes...
|
||||
// E.g., 0.000000000...000.
|
||||
UC const * start = start_digits;
|
||||
while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
|
||||
if(*start == UC('0')) { digit_count --; }
|
||||
start++;
|
||||
}
|
||||
if (digit_count > 19) {
|
||||
answer.too_many_digits = true;
|
||||
// Let us start again, this time, avoiding overflows.
|
||||
// We don't need to check if is_integer, since we use the
|
||||
// pre-tokenized spans from above.
|
||||
i = 0;
|
||||
p = answer.integer.ptr;
|
||||
UC const * int_end = p + answer.integer.len();
|
||||
constexpr uint64_t minimal_nineteen_digit_integer{1000000000000000000};
|
||||
while((i < minimal_nineteen_digit_integer) && (p != int_end)) {
|
||||
i = i * 10 + uint64_t(*p - UC('0'));
|
||||
++p;
|
||||
}
|
||||
if (i >= minimal_nineteen_digit_integer) { // We have a big integers
|
||||
exponent = end_of_integer_part - p + exp_number;
|
||||
} else { // We have a value with a fractional component.
|
||||
p = answer.fraction.ptr;
|
||||
UC const * frac_end = p + answer.fraction.len();
|
||||
while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
|
||||
i = i * 10 + uint64_t(*p - UC('0'));
|
||||
++p;
|
||||
}
|
||||
exponent = answer.fraction.ptr - p + exp_number;
|
||||
}
|
||||
// We have now corrected both exponent and i, to a truncated value
|
||||
}
|
||||
}
|
||||
answer.exponent = exponent;
|
||||
answer.mantissa = i;
|
||||
return answer;
|
||||
}
|
||||
|
||||
}}}}}} // namespace s
|
||||
|
||||
#endif
|
||||
+623
@@ -0,0 +1,623 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_BIGINT_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_BIGINT_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
// the limb width: we want efficient multiplication of double the bits in
|
||||
// limb, or for 64-bit limbs, at least 64-bit multiplication where we can
|
||||
// extract the high and low parts efficiently. this is every 64-bit
|
||||
// architecture except for sparc, which emulates 128-bit multiplication.
|
||||
// we might have platforms where `CHAR_BIT` is not 8, so let's avoid
|
||||
// doing `8 * sizeof(limb)`.
|
||||
#if defined(BOOST_JSON_FASTFLOAT_64BIT) && !defined(__sparc)
|
||||
#define BOOST_JSON_FASTFLOAT_64BIT_LIMB 1
|
||||
typedef uint64_t limb;
|
||||
constexpr size_t limb_bits = 64;
|
||||
#else
|
||||
#define BOOST_JSON_FASTFLOAT_32BIT_LIMB
|
||||
typedef uint32_t limb;
|
||||
constexpr size_t limb_bits = 32;
|
||||
#endif
|
||||
|
||||
typedef span<limb> limb_span;
|
||||
|
||||
// number of bits in a bigint. this needs to be at least the number
|
||||
// of bits required to store the largest bigint, which is
|
||||
// `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or
|
||||
// ~3600 bits, so we round to 4000.
|
||||
constexpr size_t bigint_bits = 4000;
|
||||
constexpr size_t bigint_limbs = bigint_bits / limb_bits;
|
||||
|
||||
// vector-like type that is allocated on the stack. the entire
|
||||
// buffer is pre-allocated, and only the length changes.
|
||||
template <uint16_t size>
|
||||
struct stackvec {
|
||||
limb data[size];
|
||||
// we never need more than 150 limbs
|
||||
uint16_t length{0};
|
||||
|
||||
stackvec() = default;
|
||||
stackvec(const stackvec &) = delete;
|
||||
stackvec &operator=(const stackvec &) = delete;
|
||||
stackvec(stackvec &&) = delete;
|
||||
stackvec &operator=(stackvec &&other) = delete;
|
||||
|
||||
// create stack vector from existing limb span.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) {
|
||||
try_extend(s);
|
||||
}
|
||||
|
||||
BOOST_JSON_CXX14_CONSTEXPR limb& operator[](size_t index) noexcept {
|
||||
BOOST_ASSERT(index < length);
|
||||
return data[index];
|
||||
}
|
||||
BOOST_JSON_CXX14_CONSTEXPR const limb& operator[](size_t index) const noexcept {
|
||||
BOOST_ASSERT(index < length);
|
||||
return data[index];
|
||||
}
|
||||
// index from the end of the container
|
||||
BOOST_JSON_CXX14_CONSTEXPR const limb& rindex(size_t index) const noexcept {
|
||||
BOOST_ASSERT(index < length);
|
||||
size_t rindex = length - index - 1;
|
||||
return data[rindex];
|
||||
}
|
||||
|
||||
// set the length, without bounds checking.
|
||||
BOOST_JSON_CXX14_CONSTEXPR void set_len(size_t len) noexcept {
|
||||
length = uint16_t(len);
|
||||
}
|
||||
constexpr size_t len() const noexcept {
|
||||
return length;
|
||||
}
|
||||
constexpr bool is_empty() const noexcept {
|
||||
return length == 0;
|
||||
}
|
||||
constexpr size_t capacity() const noexcept {
|
||||
return size;
|
||||
}
|
||||
// append item to vector, without bounds checking
|
||||
BOOST_JSON_CXX14_CONSTEXPR void push_unchecked(limb value) noexcept {
|
||||
data[length] = value;
|
||||
length++;
|
||||
}
|
||||
// append item to vector, returning if item was added
|
||||
BOOST_JSON_CXX14_CONSTEXPR bool try_push(limb value) noexcept {
|
||||
if (len() < capacity()) {
|
||||
push_unchecked(value);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// add items to the vector, from a span, without bounds checking
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept {
|
||||
limb* ptr = data + length;
|
||||
std::copy_n(s.ptr, s.len(), ptr);
|
||||
set_len(len() + s.len());
|
||||
}
|
||||
// try to add items to the vector, returning if items were added
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept {
|
||||
if (len() + s.len() <= capacity()) {
|
||||
extend_unchecked(s);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// resize the vector, without bounds checking
|
||||
// if the new size is longer than the vector, assign value to each
|
||||
// appended item.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void resize_unchecked(size_t new_len, limb value) noexcept {
|
||||
if (new_len > len()) {
|
||||
size_t count = new_len - len();
|
||||
limb* first = data + len();
|
||||
limb* last = first + count;
|
||||
::std::fill(first, last, value);
|
||||
set_len(new_len);
|
||||
} else {
|
||||
set_len(new_len);
|
||||
}
|
||||
}
|
||||
// try to resize the vector, returning if the vector was resized.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept {
|
||||
if (new_len > capacity()) {
|
||||
return false;
|
||||
} else {
|
||||
resize_unchecked(new_len, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// check if any limbs are non-zero after the given index.
|
||||
// this needs to be done in reverse order, since the index
|
||||
// is relative to the most significant limbs.
|
||||
BOOST_JSON_CXX14_CONSTEXPR bool nonzero(size_t index) const noexcept {
|
||||
while (index < len()) {
|
||||
if (rindex(index) != 0) {
|
||||
return true;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// normalize the big integer, so most-significant zero limbs are removed.
|
||||
BOOST_JSON_CXX14_CONSTEXPR void normalize() noexcept {
|
||||
while (len() > 0 && rindex(0) == 0) {
|
||||
length--;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
uint64_t empty_hi64(bool& truncated) noexcept {
|
||||
truncated = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint64_hi64(uint64_t r0, bool& truncated) noexcept {
|
||||
truncated = false;
|
||||
int shl = leading_zeroes(r0);
|
||||
return r0 << shl;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool& truncated) noexcept {
|
||||
int shl = leading_zeroes(r0);
|
||||
if (shl == 0) {
|
||||
truncated = r1 != 0;
|
||||
return r0;
|
||||
} else {
|
||||
int shr = 64 - shl;
|
||||
truncated = (r1 << shl) != 0;
|
||||
return (r0 << shl) | (r1 >> shr);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint32_hi64(uint32_t r0, bool& truncated) noexcept {
|
||||
return uint64_hi64(r0, truncated);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint32_hi64(uint32_t r0, uint32_t r1, bool& truncated) noexcept {
|
||||
uint64_t x0 = r0;
|
||||
uint64_t x1 = r1;
|
||||
return uint64_hi64((x0 << 32) | x1, truncated);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
uint64_t uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool& truncated) noexcept {
|
||||
uint64_t x0 = r0;
|
||||
uint64_t x1 = r1;
|
||||
uint64_t x2 = r2;
|
||||
return uint64_hi64(x0, (x1 << 32) | x2, truncated);
|
||||
}
|
||||
|
||||
// add two small integers, checking for overflow.
|
||||
// we want an efficient operation. for msvc, where
|
||||
// we don't have built-in intrinsics, this is still
|
||||
// pretty fast.
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
limb scalar_add(limb x, limb y, bool& overflow) noexcept {
|
||||
limb z;
|
||||
// gcc and clang
|
||||
#if defined(__has_builtin)
|
||||
#if __has_builtin(__builtin_add_overflow)
|
||||
if (!cpp20_and_in_constexpr()) {
|
||||
overflow = __builtin_add_overflow(x, y, &z);
|
||||
return z;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// generic, this still optimizes correctly on MSVC.
|
||||
z = x + y;
|
||||
overflow = z < x;
|
||||
return z;
|
||||
}
|
||||
|
||||
// multiply two small integers, getting both the high and low bits.
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
limb scalar_mul(limb x, limb y, limb& carry) noexcept {
|
||||
#ifdef BOOST_JSON_FASTFLOAT_64BIT_LIMB
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
// GCC and clang both define it as an extension.
|
||||
__uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);
|
||||
carry = limb(z >> limb_bits);
|
||||
return limb(z);
|
||||
#else
|
||||
// fallback, no native 128-bit integer multiplication with carry.
|
||||
// on msvc, this optimizes identically, somehow.
|
||||
value128 z = full_multiplication(x, y);
|
||||
bool overflow;
|
||||
z.low = scalar_add(z.low, carry, overflow);
|
||||
z.high += uint64_t(overflow); // cannot overflow
|
||||
carry = z.high;
|
||||
return z.low;
|
||||
#endif
|
||||
#else
|
||||
uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);
|
||||
carry = limb(z >> limb_bits);
|
||||
return limb(z);
|
||||
#endif
|
||||
}
|
||||
|
||||
// add scalar value to bigint starting from offset.
|
||||
// used in grade school multiplication
|
||||
template <uint16_t size>
|
||||
inline BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool small_add_from(stackvec<size>& vec, limb y, size_t start) noexcept {
|
||||
size_t index = start;
|
||||
limb carry = y;
|
||||
bool overflow;
|
||||
while (carry != 0 && index < vec.len()) {
|
||||
vec[index] = scalar_add(vec[index], carry, overflow);
|
||||
carry = limb(overflow);
|
||||
index += 1;
|
||||
}
|
||||
if (carry != 0) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(vec.try_push(carry));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// add scalar value to bigint.
|
||||
template <uint16_t size>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool small_add(stackvec<size>& vec, limb y) noexcept {
|
||||
return small_add_from(vec, y, 0);
|
||||
}
|
||||
|
||||
// multiply bigint by scalar value.
|
||||
template <uint16_t size>
|
||||
inline BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool small_mul(stackvec<size>& vec, limb y) noexcept {
|
||||
limb carry = 0;
|
||||
for (size_t index = 0; index < vec.len(); index++) {
|
||||
vec[index] = scalar_mul(vec[index], y, carry);
|
||||
}
|
||||
if (carry != 0) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(vec.try_push(carry));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// add bigint to bigint starting from index.
|
||||
// used in grade school multiplication
|
||||
template <uint16_t size>
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool large_add_from(stackvec<size>& x, limb_span y, size_t start) noexcept {
|
||||
// the effective x buffer is from `xstart..x.len()`, so exit early
|
||||
// if we can't get that current range.
|
||||
if (x.len() < start || y.len() > x.len() - start) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));
|
||||
}
|
||||
|
||||
bool carry = false;
|
||||
for (size_t index = 0; index < y.len(); index++) {
|
||||
limb xi = x[index + start];
|
||||
limb yi = y[index];
|
||||
bool c1 = false;
|
||||
bool c2 = false;
|
||||
xi = scalar_add(xi, yi, c1);
|
||||
if (carry) {
|
||||
xi = scalar_add(xi, 1, c2);
|
||||
}
|
||||
x[index + start] = xi;
|
||||
carry = c1 | c2;
|
||||
}
|
||||
|
||||
// handle overflow
|
||||
if (carry) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// add bigint to bigint.
|
||||
template <uint16_t size>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool large_add_from(stackvec<size>& x, limb_span y) noexcept {
|
||||
return large_add_from(x, y, 0);
|
||||
}
|
||||
|
||||
// grade-school multiplication algorithm
|
||||
template <uint16_t size>
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool long_mul(stackvec<size>& x, limb_span y) noexcept {
|
||||
limb_span xs = limb_span(x.data, x.len());
|
||||
stackvec<size> z(xs);
|
||||
limb_span zs = limb_span(z.data, z.len());
|
||||
|
||||
if (y.len() != 0) {
|
||||
limb y0 = y[0];
|
||||
BOOST_JSON_FASTFLOAT_TRY(small_mul(x, y0));
|
||||
for (size_t index = 1; index < y.len(); index++) {
|
||||
limb yi = y[index];
|
||||
stackvec<size> zi;
|
||||
if (yi != 0) {
|
||||
// re-use the same buffer throughout
|
||||
zi.set_len(0);
|
||||
BOOST_JSON_FASTFLOAT_TRY(zi.try_extend(zs));
|
||||
BOOST_JSON_FASTFLOAT_TRY(small_mul(zi, yi));
|
||||
limb_span zis = limb_span(zi.data, zi.len());
|
||||
BOOST_JSON_FASTFLOAT_TRY(large_add_from(x, zis, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x.normalize();
|
||||
return true;
|
||||
}
|
||||
|
||||
// grade-school multiplication algorithm
|
||||
template <uint16_t size>
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool large_mul(stackvec<size>& x, limb_span y) noexcept {
|
||||
if (y.len() == 1) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(small_mul(x, y[0]));
|
||||
} else {
|
||||
BOOST_JSON_FASTFLOAT_TRY(long_mul(x, y));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename = void>
|
||||
struct pow5_tables {
|
||||
static constexpr uint32_t large_step = 135;
|
||||
static constexpr uint64_t small_power_of_5[] = {
|
||||
1UL, 5UL, 25UL, 125UL, 625UL, 3125UL, 15625UL, 78125UL, 390625UL,
|
||||
1953125UL, 9765625UL, 48828125UL, 244140625UL, 1220703125UL,
|
||||
6103515625UL, 30517578125UL, 152587890625UL, 762939453125UL,
|
||||
3814697265625UL, 19073486328125UL, 95367431640625UL, 476837158203125UL,
|
||||
2384185791015625UL, 11920928955078125UL, 59604644775390625UL,
|
||||
298023223876953125UL, 1490116119384765625UL, 7450580596923828125UL,
|
||||
};
|
||||
#ifdef BOOST_JSON_FASTFLOAT_64BIT_LIMB
|
||||
constexpr static limb large_power_of_5[] = {
|
||||
1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,
|
||||
10482974169319127550UL, 198276706040285095UL};
|
||||
#else
|
||||
constexpr static limb large_power_of_5[] = {
|
||||
4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U,
|
||||
1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U};
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr uint32_t pow5_tables<T>::large_step;
|
||||
|
||||
template <typename T>
|
||||
constexpr uint64_t pow5_tables<T>::small_power_of_5[];
|
||||
|
||||
template <typename T>
|
||||
constexpr limb pow5_tables<T>::large_power_of_5[];
|
||||
|
||||
// big integer type. implements a small subset of big integer
|
||||
// arithmetic, using simple algorithms since asymptotically
|
||||
// faster algorithms are slower for a small number of limbs.
|
||||
// all operations assume the big-integer is normalized.
|
||||
struct bigint : pow5_tables<> {
|
||||
// storage of the limbs, in little-endian order.
|
||||
stackvec<bigint_limbs> vec;
|
||||
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bigint(): vec() {}
|
||||
bigint(const bigint &) = delete;
|
||||
bigint &operator=(const bigint &) = delete;
|
||||
bigint(bigint &&) = delete;
|
||||
bigint &operator=(bigint &&other) = delete;
|
||||
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bigint(uint64_t value): vec() {
|
||||
#ifdef BOOST_JSON_FASTFLOAT_64BIT_LIMB
|
||||
vec.push_unchecked(value);
|
||||
#else
|
||||
vec.push_unchecked(uint32_t(value));
|
||||
vec.push_unchecked(uint32_t(value >> 32));
|
||||
#endif
|
||||
vec.normalize();
|
||||
}
|
||||
|
||||
// get the high 64 bits from the vector, and if bits were truncated.
|
||||
// this is to get the significant digits for the float.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool& truncated) const noexcept {
|
||||
#ifdef BOOST_JSON_FASTFLOAT_64BIT_LIMB
|
||||
if (vec.len() == 0) {
|
||||
return empty_hi64(truncated);
|
||||
} else if (vec.len() == 1) {
|
||||
return uint64_hi64(vec.rindex(0), truncated);
|
||||
} else {
|
||||
uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated);
|
||||
truncated |= vec.nonzero(2);
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
if (vec.len() == 0) {
|
||||
return empty_hi64(truncated);
|
||||
} else if (vec.len() == 1) {
|
||||
return uint32_hi64(vec.rindex(0), truncated);
|
||||
} else if (vec.len() == 2) {
|
||||
return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated);
|
||||
} else {
|
||||
uint64_t result = uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);
|
||||
truncated |= vec.nonzero(3);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// compare two big integers, returning the large value.
|
||||
// assumes both are normalized. if the return value is
|
||||
// negative, other is larger, if the return value is
|
||||
// positive, this is larger, otherwise they are equal.
|
||||
// the limbs are stored in little-endian order, so we
|
||||
// must compare the limbs in ever order.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 int compare(const bigint& other) const noexcept {
|
||||
if (vec.len() > other.vec.len()) {
|
||||
return 1;
|
||||
} else if (vec.len() < other.vec.len()) {
|
||||
return -1;
|
||||
} else {
|
||||
for (size_t index = vec.len(); index > 0; index--) {
|
||||
limb xi = vec[index - 1];
|
||||
limb yi = other.vec[index - 1];
|
||||
if (xi > yi) {
|
||||
return 1;
|
||||
} else if (xi < yi) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// shift left each limb n bits, carrying over to the new limb
|
||||
// returns true if we were able to shift all the digits.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept {
|
||||
// Internally, for each item, we shift left by n, and add the previous
|
||||
// right shifted limb-bits.
|
||||
// For example, we transform (for u8) shifted left 2, to:
|
||||
// b10100100 b01000010
|
||||
// b10 b10010001 b00001000
|
||||
BOOST_ASSERT(n != 0);
|
||||
BOOST_ASSERT(n < sizeof(limb) * 8);
|
||||
|
||||
size_t shl = n;
|
||||
size_t shr = limb_bits - shl;
|
||||
limb prev = 0;
|
||||
for (size_t index = 0; index < vec.len(); index++) {
|
||||
limb xi = vec[index];
|
||||
vec[index] = (xi << shl) | (prev >> shr);
|
||||
prev = xi;
|
||||
}
|
||||
|
||||
limb carry = prev >> shr;
|
||||
if (carry != 0) {
|
||||
return vec.try_push(carry);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// move the limbs left by `n` limbs.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept {
|
||||
BOOST_ASSERT(n != 0);
|
||||
if (n + vec.len() > vec.capacity()) {
|
||||
return false;
|
||||
} else if (!vec.is_empty()) {
|
||||
// move limbs
|
||||
limb* dst = vec.data + n;
|
||||
const limb* src = vec.data;
|
||||
std::copy_backward(src, src + vec.len(), dst + vec.len());
|
||||
// fill in empty limbs
|
||||
limb* first = vec.data;
|
||||
limb* last = first + n;
|
||||
::std::fill(first, last, 0);
|
||||
vec.set_len(n + vec.len());
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// move the limbs left by `n` bits.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept {
|
||||
size_t rem = n % limb_bits;
|
||||
size_t div = n / limb_bits;
|
||||
if (rem != 0) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(shl_bits(rem));
|
||||
}
|
||||
if (div != 0) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(shl_limbs(div));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the number of leading zeros in the bigint.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept {
|
||||
if (vec.is_empty()) {
|
||||
return 0;
|
||||
} else {
|
||||
#ifdef BOOST_JSON_FASTFLOAT_64BIT_LIMB
|
||||
return leading_zeroes(vec.rindex(0));
|
||||
#else
|
||||
// no use defining a specialized leading_zeroes for a 32-bit type.
|
||||
uint64_t r0 = vec.rindex(0);
|
||||
return leading_zeroes(r0 << 32);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// get the number of bits in the bigint.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept {
|
||||
int lz = ctlz();
|
||||
return int(limb_bits * vec.len()) - lz;
|
||||
}
|
||||
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept {
|
||||
return small_mul(vec, y);
|
||||
}
|
||||
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept {
|
||||
return small_add(vec, y);
|
||||
}
|
||||
|
||||
// multiply as if by 2 raised to a power.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept {
|
||||
return shl(exp);
|
||||
}
|
||||
|
||||
// multiply as if by 5 raised to a power.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept {
|
||||
// multiply by a power of 5
|
||||
constexpr size_t large_length = sizeof(large_power_of_5) / sizeof(limb);
|
||||
limb_span large = limb_span(large_power_of_5, large_length);
|
||||
while (exp >= large_step) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(large_mul(vec, large));
|
||||
exp -= large_step;
|
||||
}
|
||||
#ifdef BOOST_JSON_FASTFLOAT_64BIT_LIMB
|
||||
constexpr uint32_t small_step = 27;
|
||||
constexpr limb max_native = 7450580596923828125UL;
|
||||
#else
|
||||
constexpr uint32_t small_step = 13;
|
||||
constexpr limb max_native = 1220703125U;
|
||||
#endif
|
||||
while (exp >= small_step) {
|
||||
BOOST_JSON_FASTFLOAT_TRY(small_mul(vec, max_native));
|
||||
exp -= small_step;
|
||||
}
|
||||
if (exp != 0) {
|
||||
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||
// This is similar to https://github.com/llvm/llvm-project/issues/47746,
|
||||
// except the workaround described there don't work here
|
||||
BOOST_JSON_FASTFLOAT_TRY(
|
||||
small_mul(vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// multiply as if by 10 raised to a power.
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept {
|
||||
BOOST_JSON_FASTFLOAT_TRY(pow5(exp));
|
||||
return pow2(exp);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}} // namespace fast_float
|
||||
|
||||
#endif
|
||||
Vendored
Executable
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_CONSTEXPR_FEATURE_DETECT_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_CONSTEXPR_FEATURE_DETECT_HPP
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||
# define BOOST_JSON_HAS_BIT_CAST
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L
|
||||
# define BOOST_JSON_HAS_IS_CONSTANT_EVALUATED
|
||||
#endif
|
||||
|
||||
// Testing for relevant C++20 constexpr library features
|
||||
#if defined(BOOST_JSON_HAS_IS_CONSTANT_EVALUATED) \
|
||||
&& defined(BOOST_JSON_HAS_BIT_CAST) \
|
||||
&& __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
|
||||
#define BOOST_JSON_FASTFLOAT_CONSTEXPR20 constexpr
|
||||
#else
|
||||
#define BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
#endif
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_FASTFLOAT_CONSTEXPR_FEATURE_DETECT_HPP
|
||||
Vendored
Executable
+196
@@ -0,0 +1,196 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_DECIMAL_TO_BINARY_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_DECIMAL_TO_BINARY_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
|
||||
#include <boost/json/detail/charconv/detail/fast_float/fast_table.hpp>
|
||||
#include <cfloat>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
// This will compute or rather approximate w * 5**q and return a pair of 64-bit words approximating
|
||||
// the result, with the "high" part corresponding to the most significant bits and the
|
||||
// low part corresponding to the least significant bits.
|
||||
//
|
||||
template <int bit_precision>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
||||
const int index = 2 * int(q - powers::smallest_power_of_five);
|
||||
// For small values of q, e.g., q in [0,27], the answer is always exact because
|
||||
// The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
|
||||
// gives the exact answer.
|
||||
value128 firstproduct = full_multiplication(w, powers::power_of_five_128[index]);
|
||||
static_assert((bit_precision >= 0) && (bit_precision <= 64), " precision should be in (0,64]");
|
||||
constexpr uint64_t precision_mask = (bit_precision < 64) ?
|
||||
(uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
|
||||
: uint64_t(0xFFFFFFFFFFFFFFFF);
|
||||
if((firstproduct.high & precision_mask) == precision_mask) { // could further guard with (lower + w < lower)
|
||||
// regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed.
|
||||
value128 secondproduct = full_multiplication(w, powers::power_of_five_128[index + 1]);
|
||||
firstproduct.low += secondproduct.high;
|
||||
if(secondproduct.high > firstproduct.low) {
|
||||
firstproduct.high++;
|
||||
}
|
||||
}
|
||||
return firstproduct;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
/**
|
||||
* For q in (0,350), we have that
|
||||
* f = (((152170 + 65536) * q ) >> 16);
|
||||
* is equal to
|
||||
* floor(p) + q
|
||||
* where
|
||||
* p = log(5**q)/log(2) = q * log(5)/log(2)
|
||||
*
|
||||
* For negative values of q in (-400,0), we have that
|
||||
* f = (((152170 + 65536) * q ) >> 16);
|
||||
* is equal to
|
||||
* -ceil(p) + q
|
||||
* where
|
||||
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
||||
*/
|
||||
constexpr BOOST_FORCEINLINE int32_t power(int32_t q) noexcept {
|
||||
return (((152170 + 65536) * q) >> 16) + 63;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
// create an adjusted mantissa, biased by the invalid power2
|
||||
// for significant digits already multiplied by 10 ** q.
|
||||
template <typename binary>
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
adjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept {
|
||||
int hilz = int(w >> 63) ^ 1;
|
||||
adjusted_mantissa answer;
|
||||
answer.mantissa = w << hilz;
|
||||
int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent();
|
||||
answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + invalid_am_bias);
|
||||
return answer;
|
||||
}
|
||||
|
||||
// w * 10 ** q, without rounding the representation up.
|
||||
// the power2 in the exponent will be adjusted by invalid_am_bias.
|
||||
template <typename binary>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept {
|
||||
int lz = leading_zeroes(w);
|
||||
w <<= lz;
|
||||
value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
|
||||
return compute_error_scaled<binary>(q, product.high, lz);
|
||||
}
|
||||
|
||||
// w * 10 ** q
|
||||
// The returned value should be a valid ieee64 number that simply need to be packed.
|
||||
// However, in some very rare cases, the computation will fail. In such cases, we
|
||||
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
|
||||
// in such cases.
|
||||
template <typename binary>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
adjusted_mantissa answer;
|
||||
if ((w == 0) || (q < binary::smallest_power_of_ten())) {
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
// result should be zero
|
||||
return answer;
|
||||
}
|
||||
if (q > binary::largest_power_of_ten()) {
|
||||
// we want to get infinity:
|
||||
answer.power2 = binary::infinite_power();
|
||||
answer.mantissa = 0;
|
||||
return answer;
|
||||
}
|
||||
// At this point in time q is in [powers::smallest_power_of_five, powers::largest_power_of_five].
|
||||
|
||||
// We want the most significant bit of i to be 1. Shift if needed.
|
||||
int lz = leading_zeroes(w);
|
||||
w <<= lz;
|
||||
|
||||
// The required precision is binary::mantissa_explicit_bits() + 3 because
|
||||
// 1. We need the implicit bit
|
||||
// 2. We need an extra bit for rounding purposes
|
||||
// 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift)
|
||||
|
||||
value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
|
||||
// The computed 'product' is always sufficient.
|
||||
// Mathematical proof:
|
||||
// Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to appear)
|
||||
// See script/mushtak_lemire.py
|
||||
|
||||
// The "compute_product_approximation" function can be slightly slower than a branchless approach:
|
||||
// value128 product = compute_product(q, w);
|
||||
// but in practice, we can win big with the compute_product_approximation if its additional branch
|
||||
// is easily predicted. Which is best is data specific.
|
||||
int upperbit = int(product.high >> 63);
|
||||
|
||||
answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
|
||||
|
||||
answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz - binary::minimum_exponent());
|
||||
if (answer.power2 <= 0) { // we have a subnormal?
|
||||
// Here have that answer.power2 <= 0 so -answer.power2 >= 0
|
||||
if(-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
|
||||
answer.power2 = 0;
|
||||
answer.mantissa = 0;
|
||||
// result should be zero
|
||||
return answer;
|
||||
}
|
||||
// next line is safe because -answer.power2 + 1 < 64
|
||||
answer.mantissa >>= -answer.power2 + 1;
|
||||
// Thankfully, we can't have both "round-to-even" and subnormals because
|
||||
// "round-to-even" only occurs for powers close to 0.
|
||||
answer.mantissa += (answer.mantissa & 1); // round up
|
||||
answer.mantissa >>= 1;
|
||||
// There is a weird scenario where we don't have a subnormal but just.
|
||||
// Suppose we start with 2.2250738585072013e-308, we end up
|
||||
// with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal
|
||||
// whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round
|
||||
// up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer
|
||||
// subnormal, but we can only know this after rounding.
|
||||
// So we only declare a subnormal if we are smaller than the threshold.
|
||||
answer.power2 = (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) ? 0 : 1;
|
||||
return answer;
|
||||
}
|
||||
|
||||
// usually, we round *up*, but if we fall right in between and and we have an
|
||||
// even basis, we need to round down
|
||||
// We are only concerned with the cases where 5**q fits in single 64-bit word.
|
||||
if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) && (q <= binary::max_exponent_round_to_even()) &&
|
||||
((answer.mantissa & 3) == 1) ) { // we may fall between two floats!
|
||||
// To be in-between two floats we need that in doing
|
||||
// answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
|
||||
// ... we dropped out only zeroes. But if this happened, then we can go back!!!
|
||||
if((answer.mantissa << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) == product.high) {
|
||||
answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up
|
||||
}
|
||||
}
|
||||
|
||||
answer.mantissa += (answer.mantissa & 1); // round up
|
||||
answer.mantissa >>= 1;
|
||||
if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) {
|
||||
answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits());
|
||||
answer.power2++; // undo previous addition
|
||||
}
|
||||
|
||||
answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits());
|
||||
if (answer.power2 >= binary::infinite_power()) { // infinity
|
||||
answer.power2 = binary::infinite_power();
|
||||
answer.mantissa = 0;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
}}}}}} // namespace fast_float
|
||||
|
||||
#endif
|
||||
Vendored
Executable
+442
@@ -0,0 +1,442 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_DIGIT_COMPARISON_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_DIGIT_COMPARISON_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
|
||||
#include <boost/json/detail/charconv/detail/fast_float/bigint.hpp>
|
||||
#include <boost/json/detail/charconv/detail/fast_float/ascii_number.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
// 1e0 to 1e19
|
||||
constexpr static uint64_t powers_of_ten_uint64[] = {
|
||||
1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,
|
||||
1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,
|
||||
100000000000000UL, 1000000000000000UL, 10000000000000000UL, 100000000000000000UL,
|
||||
1000000000000000000UL, 10000000000000000000UL};
|
||||
|
||||
// calculate the exponent, in scientific notation, of the number.
|
||||
// this algorithm is not even close to optimized, but it has no practical
|
||||
// effect on performance: in order to have a faster algorithm, we'd need
|
||||
// to slow down performance for faster algorithms, and this is still fast.
|
||||
template <typename UC>
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept {
|
||||
uint64_t mantissa = num.mantissa;
|
||||
int32_t exponent = int32_t(num.exponent);
|
||||
while (mantissa >= 10000) {
|
||||
mantissa /= 10000;
|
||||
exponent += 4;
|
||||
}
|
||||
while (mantissa >= 100) {
|
||||
mantissa /= 100;
|
||||
exponent += 2;
|
||||
}
|
||||
while (mantissa >= 10) {
|
||||
mantissa /= 10;
|
||||
exponent += 1;
|
||||
}
|
||||
return exponent;
|
||||
}
|
||||
|
||||
// this converts a native floating-point number to an extended-precision float.
|
||||
template <typename T>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa to_extended(T value) noexcept {
|
||||
using equiv_uint = typename binary_format<T>::equiv_uint;
|
||||
constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
|
||||
constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
|
||||
constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
|
||||
|
||||
adjusted_mantissa am;
|
||||
int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
|
||||
equiv_uint bits;
|
||||
#ifdef BOOST_JSON_HAS_BIT_CAST
|
||||
bits = std::bit_cast<equiv_uint>(value);
|
||||
#else
|
||||
::memcpy(&bits, &value, sizeof(T));
|
||||
#endif
|
||||
if ((bits & exponent_mask) == 0) {
|
||||
// denormal
|
||||
am.power2 = 1 - bias;
|
||||
am.mantissa = bits & mantissa_mask;
|
||||
} else {
|
||||
// normal
|
||||
am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());
|
||||
am.power2 -= bias;
|
||||
am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
|
||||
}
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
// get the extended precision value of the halfway point between b and b+u.
|
||||
// we are given a native float that represents b, so we need to adjust it
|
||||
// halfway between b and b+u.
|
||||
template <typename T>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa to_extended_halfway(T value) noexcept {
|
||||
adjusted_mantissa am = to_extended(value);
|
||||
am.mantissa <<= 1;
|
||||
am.mantissa += 1;
|
||||
am.power2 -= 1;
|
||||
return am;
|
||||
}
|
||||
|
||||
// round an extended-precision float to the nearest machine float.
|
||||
template <typename T, typename callback>
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
void round(adjusted_mantissa& am, callback cb) noexcept {
|
||||
int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1;
|
||||
if (-am.power2 >= mantissa_shift) {
|
||||
// have a denormal float
|
||||
int32_t shift = -am.power2 + 1;
|
||||
cb(am, std::min<int32_t>(shift, 64));
|
||||
// check for round-up: if rounding-nearest carried us to the hidden bit.
|
||||
am.power2 = (am.mantissa < (uint64_t(1) << binary_format<T>::mantissa_explicit_bits())) ? 0 : 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// have a normal float, use the default shift.
|
||||
cb(am, mantissa_shift);
|
||||
|
||||
// check for carry
|
||||
if (am.mantissa >= (uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {
|
||||
am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
|
||||
am.power2++;
|
||||
}
|
||||
|
||||
// check for infinite: we could have carried to an infinite power
|
||||
am.mantissa &= ~(uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
|
||||
if (am.power2 >= binary_format<T>::infinite_power()) {
|
||||
am.power2 = binary_format<T>::infinite_power();
|
||||
am.mantissa = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename callback>
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
void round_nearest_tie_even(adjusted_mantissa& am, int32_t shift, callback cb) noexcept {
|
||||
const uint64_t mask
|
||||
= (shift == 64)
|
||||
? UINT64_MAX
|
||||
: (uint64_t(1) << shift) - 1;
|
||||
const uint64_t halfway
|
||||
= (shift == 0)
|
||||
? 0
|
||||
: uint64_t(1) << (shift - 1);
|
||||
uint64_t truncated_bits = am.mantissa & mask;
|
||||
bool is_above = truncated_bits > halfway;
|
||||
bool is_halfway = truncated_bits == halfway;
|
||||
|
||||
// shift digits into position
|
||||
if (shift == 64) {
|
||||
am.mantissa = 0;
|
||||
} else {
|
||||
am.mantissa >>= shift;
|
||||
}
|
||||
am.power2 += shift;
|
||||
|
||||
bool is_odd = (am.mantissa & 1) == 1;
|
||||
am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
|
||||
if (shift == 64) {
|
||||
am.mantissa = 0;
|
||||
} else {
|
||||
am.mantissa >>= shift;
|
||||
}
|
||||
am.power2 += shift;
|
||||
}
|
||||
template <typename UC>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void skip_zeros(UC const * & first, UC const * last) noexcept {
|
||||
uint64_t val;
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != int_cmp_zeros<UC>()) {
|
||||
break;
|
||||
}
|
||||
first += int_cmp_len<UC>();
|
||||
}
|
||||
while (first != last) {
|
||||
if (*first != UC('0')) {
|
||||
break;
|
||||
}
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
// determine if any non-zero digits were truncated.
|
||||
// all characters must be valid digits.
|
||||
template <typename UC>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(UC const * first, UC const * last) noexcept {
|
||||
// do 8-bit optimizations, can just compare to 8 literal 0s.
|
||||
uint64_t val;
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != int_cmp_zeros<UC>()) {
|
||||
return true;
|
||||
}
|
||||
first += int_cmp_len<UC>();
|
||||
}
|
||||
while (first != last) {
|
||||
if (*first != UC('0')) {
|
||||
return true;
|
||||
}
|
||||
++first;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <typename UC>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(span<const UC> s) noexcept {
|
||||
return is_truncated(s.ptr, s.ptr + s.len());
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void parse_eight_digits(const char16_t*& , limb& , size_t& , size_t& ) noexcept {
|
||||
// currently unused
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void parse_eight_digits(const char32_t*& , limb& , size_t& , size_t& ) noexcept {
|
||||
// currently unused
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
value = value * 100000000 + parse_eight_digits_unrolled(p);
|
||||
p += 8;
|
||||
counter += 8;
|
||||
count += 8;
|
||||
}
|
||||
|
||||
template <typename UC>
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
void parse_one_digit(UC const *& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
value = value * 10 + limb(*p - UC('0'));
|
||||
p++;
|
||||
counter++;
|
||||
count++;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void add_native(bigint& big, limb power, limb value) noexcept {
|
||||
big.mul(power);
|
||||
big.add(value);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void round_up_bigint(bigint& big, size_t& count) noexcept {
|
||||
// need to round-up the digits, but need to avoid rounding
|
||||
// ....9999 to ...10000, which could cause a false halfway point.
|
||||
add_native(big, 10, 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
// parse the significant digits into a big integer
|
||||
template <typename UC>
|
||||
inline BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void parse_mantissa(bigint& result, parsed_number_string_t<UC>& num, size_t max_digits, size_t& digits) noexcept {
|
||||
// try to minimize the number of big integer and scalar multiplication.
|
||||
// therefore, try to parse 8 digits at a time, and multiply by the largest
|
||||
// scalar value (9 or 19 digits) for each step.
|
||||
size_t counter = 0;
|
||||
digits = 0;
|
||||
limb value = 0;
|
||||
#ifdef BOOST_JSON_FASTFLOAT_64BIT_LIMB
|
||||
constexpr size_t step = 19;
|
||||
#else
|
||||
constexpr size_t step = 9;
|
||||
#endif
|
||||
|
||||
// process all integer digits.
|
||||
UC const * p = num.integer.ptr;
|
||||
UC const * pend = p + num.integer.len();
|
||||
skip_zeros(p, pend);
|
||||
// process all digits, in increments of step per loop
|
||||
while (p != pend) {
|
||||
if (std::is_same<UC,char>::value) {
|
||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
||||
parse_eight_digits(p, value, counter, digits);
|
||||
}
|
||||
}
|
||||
while (counter < step && p != pend && digits < max_digits) {
|
||||
parse_one_digit(p, value, counter, digits);
|
||||
}
|
||||
if (digits == max_digits) {
|
||||
// add the temporary value, then check if we've truncated any digits
|
||||
add_native(result, limb(powers_of_ten_uint64[counter]), value);
|
||||
bool truncated = is_truncated(p, pend);
|
||||
if (num.fraction.ptr != nullptr) {
|
||||
truncated |= is_truncated(num.fraction);
|
||||
}
|
||||
if (truncated) {
|
||||
round_up_bigint(result, digits);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
add_native(result, limb(powers_of_ten_uint64[counter]), value);
|
||||
counter = 0;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// add our fraction digits, if they're available.
|
||||
if (num.fraction.ptr != nullptr) {
|
||||
p = num.fraction.ptr;
|
||||
pend = p + num.fraction.len();
|
||||
if (digits == 0) {
|
||||
skip_zeros(p, pend);
|
||||
}
|
||||
// process all digits, in increments of step per loop
|
||||
while (p != pend) {
|
||||
if (std::is_same<UC,char>::value) {
|
||||
while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
|
||||
parse_eight_digits(p, value, counter, digits);
|
||||
}
|
||||
}
|
||||
while (counter < step && p != pend && digits < max_digits) {
|
||||
parse_one_digit(p, value, counter, digits);
|
||||
}
|
||||
if (digits == max_digits) {
|
||||
// add the temporary value, then check if we've truncated any digits
|
||||
add_native(result, limb(powers_of_ten_uint64[counter]), value);
|
||||
bool truncated = is_truncated(p, pend);
|
||||
if (truncated) {
|
||||
round_up_bigint(result, digits);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
add_native(result, limb(powers_of_ten_uint64[counter]), value);
|
||||
counter = 0;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (counter != 0) {
|
||||
add_native(result, limb(powers_of_ten_uint64[counter]), value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept {
|
||||
bigmant.pow10(uint32_t(exponent));
|
||||
adjusted_mantissa answer;
|
||||
bool truncated;
|
||||
answer.mantissa = bigmant.hi64(truncated);
|
||||
int bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();
|
||||
answer.power2 = bigmant.bit_length() - 64 + bias;
|
||||
|
||||
round<T>(answer, [truncated](adjusted_mantissa& a, int32_t shift) {
|
||||
round_nearest_tie_even(a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool {
|
||||
return is_above || (is_halfway && truncated) || (is_odd && is_halfway);
|
||||
});
|
||||
});
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
// the scaling here is quite simple: we have, for the real digits `m * 10^e`,
|
||||
// and for the theoretical digits `n * 2^f`. Since `e` is always negative,
|
||||
// to scale them identically, we do `n * 2^f * 5^-f`, so we now have `m * 2^e`.
|
||||
// we then need to scale by `2^(f- e)`, and then the two significant digits
|
||||
// are of the same magnitude.
|
||||
template <typename T>
|
||||
inline BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
|
||||
bigint& real_digits = bigmant;
|
||||
int32_t real_exp = exponent;
|
||||
|
||||
// get the value of `b`, rounded down, and get a bigint representation of b+h
|
||||
adjusted_mantissa am_b = am;
|
||||
// gcc7 buf: use a lambda to remove the noexcept qualifier bug with -Wnoexcept-type.
|
||||
round<T>(am_b, [](adjusted_mantissa&a, int32_t shift) { round_down(a, shift); });
|
||||
T b;
|
||||
to_float(false, am_b, b);
|
||||
adjusted_mantissa theor = to_extended_halfway(b);
|
||||
bigint theor_digits(theor.mantissa);
|
||||
int32_t theor_exp = theor.power2;
|
||||
|
||||
// scale real digits and theor digits to be same power.
|
||||
int32_t pow2_exp = theor_exp - real_exp;
|
||||
uint32_t pow5_exp = uint32_t(-real_exp);
|
||||
if (pow5_exp != 0) {
|
||||
theor_digits.pow5(pow5_exp);
|
||||
}
|
||||
if (pow2_exp > 0) {
|
||||
theor_digits.pow2(uint32_t(pow2_exp));
|
||||
} else if (pow2_exp < 0) {
|
||||
real_digits.pow2(uint32_t(-pow2_exp));
|
||||
}
|
||||
|
||||
// compare digits, and use it to director rounding
|
||||
int ord = real_digits.compare(theor_digits);
|
||||
adjusted_mantissa answer = am;
|
||||
round<T>(answer, [ord](adjusted_mantissa& a, int32_t shift) {
|
||||
round_nearest_tie_even(a, shift, [ord](bool is_odd, bool, bool) -> bool {
|
||||
if (ord > 0) {
|
||||
return true;
|
||||
} else if (ord < 0) {
|
||||
return false;
|
||||
} else {
|
||||
return is_odd;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
// parse the significant digits as a big integer to unambiguously round
|
||||
// the significant digits. here, we are trying to determine how to round
|
||||
// an extended float representation close to `b+h`, halfway between `b`
|
||||
// (the float rounded-down) and `b+u`, the next positive float. this
|
||||
// algorithm is always correct, and uses one of two approaches. when
|
||||
// the exponent is positive relative to the significant digits (such as
|
||||
// 1234), we create a big-integer representation, get the high 64-bits,
|
||||
// determine if any lower bits are truncated, and use that to direct
|
||||
// rounding. in case of a negative exponent relative to the significant
|
||||
// digits (such as 1.2345), we create a theoretical representation of
|
||||
// `b` as a big-integer type, scaled to the same binary exponent as
|
||||
// the actual digits. we then compare the big integer representations
|
||||
// of both, and use that to direct rounding.
|
||||
template <typename T, typename UC>
|
||||
inline BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa digit_comp(parsed_number_string_t<UC>& num, adjusted_mantissa am) noexcept {
|
||||
// remove the invalid exponent bias
|
||||
am.power2 -= invalid_am_bias;
|
||||
|
||||
int32_t sci_exp = scientific_exponent(num);
|
||||
size_t max_digits = binary_format<T>::max_digits();
|
||||
size_t digits = 0;
|
||||
bigint bigmant;
|
||||
parse_mantissa(bigmant, num, max_digits, digits);
|
||||
// can't underflow, since digits is at most max_digits.
|
||||
int32_t exponent = sci_exp + 1 - int32_t(digits);
|
||||
if (exponent >= 0) {
|
||||
return positive_digit_comp<T>(bigmant, exponent);
|
||||
} else {
|
||||
return negative_digit_comp<T>(bigmant, am, exponent);
|
||||
}
|
||||
}
|
||||
|
||||
}}}}}} // namespace fast_float
|
||||
|
||||
#endif
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FAST_FLOAT_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FAST_FLOAT_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
/**
|
||||
* This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
|
||||
* a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale.
|
||||
* The resulting floating-point value is the closest floating-point values (using either float or double),
|
||||
* using the "round to even" convention for values that would otherwise fall right in-between two values.
|
||||
* That is, we provide exact parsing according to the IEEE standard.
|
||||
*
|
||||
* Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
|
||||
* parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
|
||||
* `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
|
||||
*
|
||||
* The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
|
||||
*
|
||||
* Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of
|
||||
* the type `fast_float::chars_format`. It is a bitset value: we check whether
|
||||
* `fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set
|
||||
* to determine whether we allow the fixed point and scientific notation respectively.
|
||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
*/
|
||||
template<typename T, typename UC = char>
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||
|
||||
/**
|
||||
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||
*/
|
||||
template<typename T, typename UC = char>
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
T &value, parse_options_t<UC> options) noexcept;
|
||||
|
||||
}}}}}} // namespace fast_float
|
||||
#include <boost/json/detail/charconv/detail/fast_float/parse_number.hpp>
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_FASTFLOAT_FAST_FLOAT_H
|
||||
+708
@@ -0,0 +1,708 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FAST_TABLE_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FAST_TABLE_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
/**
|
||||
* When mapping numbers from decimal to binary,
|
||||
* we go from w * 10^q to m * 2^p but we have
|
||||
* 10^q = 5^q * 2^q, so effectively
|
||||
* we are trying to match
|
||||
* w * 2^q * 5^q to m * 2^p. Thus the powers of two
|
||||
* are not a concern since they can be represented
|
||||
* exactly using the binary notation, only the powers of five
|
||||
* affect the binary significand.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The smallest non-zero float (binary64) is 2^-1074.
|
||||
* We take as input numbers of the form w x 10^q where w < 2^64.
|
||||
* We have that w * 10^-343 < 2^(64-344) 5^-343 < 2^-1076.
|
||||
* However, we have that
|
||||
* (2^64-1) * 10^-342 = (2^64-1) * 2^-342 * 5^-342 > 2^-1074.
|
||||
* Thus it is possible for a number of the form w * 10^-342 where
|
||||
* w is a 64-bit value to be a non-zero floating-point number.
|
||||
*********
|
||||
* Any number of form w * 10^309 where w>= 1 is going to be
|
||||
* infinite in binary64 so we never need to worry about powers
|
||||
* of 5 greater than 308.
|
||||
*/
|
||||
template <class unused = void>
|
||||
struct powers_template {
|
||||
|
||||
constexpr static int smallest_power_of_five = binary_format<double>::smallest_power_of_ten();
|
||||
constexpr static int largest_power_of_five = binary_format<double>::largest_power_of_ten();
|
||||
constexpr static int number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1);
|
||||
// Powers of five from 5^-342 all the way to 5^308 rounded toward one.
|
||||
constexpr static uint64_t power_of_five_128[number_of_entries] = {
|
||||
0xeef453d6923bd65a,0x113faa2906a13b3f,
|
||||
0x9558b4661b6565f8,0x4ac7ca59a424c507,
|
||||
0xbaaee17fa23ebf76,0x5d79bcf00d2df649,
|
||||
0xe95a99df8ace6f53,0xf4d82c2c107973dc,
|
||||
0x91d8a02bb6c10594,0x79071b9b8a4be869,
|
||||
0xb64ec836a47146f9,0x9748e2826cdee284,
|
||||
0xe3e27a444d8d98b7,0xfd1b1b2308169b25,
|
||||
0x8e6d8c6ab0787f72,0xfe30f0f5e50e20f7,
|
||||
0xb208ef855c969f4f,0xbdbd2d335e51a935,
|
||||
0xde8b2b66b3bc4723,0xad2c788035e61382,
|
||||
0x8b16fb203055ac76,0x4c3bcb5021afcc31,
|
||||
0xaddcb9e83c6b1793,0xdf4abe242a1bbf3d,
|
||||
0xd953e8624b85dd78,0xd71d6dad34a2af0d,
|
||||
0x87d4713d6f33aa6b,0x8672648c40e5ad68,
|
||||
0xa9c98d8ccb009506,0x680efdaf511f18c2,
|
||||
0xd43bf0effdc0ba48,0x212bd1b2566def2,
|
||||
0x84a57695fe98746d,0x14bb630f7604b57,
|
||||
0xa5ced43b7e3e9188,0x419ea3bd35385e2d,
|
||||
0xcf42894a5dce35ea,0x52064cac828675b9,
|
||||
0x818995ce7aa0e1b2,0x7343efebd1940993,
|
||||
0xa1ebfb4219491a1f,0x1014ebe6c5f90bf8,
|
||||
0xca66fa129f9b60a6,0xd41a26e077774ef6,
|
||||
0xfd00b897478238d0,0x8920b098955522b4,
|
||||
0x9e20735e8cb16382,0x55b46e5f5d5535b0,
|
||||
0xc5a890362fddbc62,0xeb2189f734aa831d,
|
||||
0xf712b443bbd52b7b,0xa5e9ec7501d523e4,
|
||||
0x9a6bb0aa55653b2d,0x47b233c92125366e,
|
||||
0xc1069cd4eabe89f8,0x999ec0bb696e840a,
|
||||
0xf148440a256e2c76,0xc00670ea43ca250d,
|
||||
0x96cd2a865764dbca,0x380406926a5e5728,
|
||||
0xbc807527ed3e12bc,0xc605083704f5ecf2,
|
||||
0xeba09271e88d976b,0xf7864a44c633682e,
|
||||
0x93445b8731587ea3,0x7ab3ee6afbe0211d,
|
||||
0xb8157268fdae9e4c,0x5960ea05bad82964,
|
||||
0xe61acf033d1a45df,0x6fb92487298e33bd,
|
||||
0x8fd0c16206306bab,0xa5d3b6d479f8e056,
|
||||
0xb3c4f1ba87bc8696,0x8f48a4899877186c,
|
||||
0xe0b62e2929aba83c,0x331acdabfe94de87,
|
||||
0x8c71dcd9ba0b4925,0x9ff0c08b7f1d0b14,
|
||||
0xaf8e5410288e1b6f,0x7ecf0ae5ee44dd9,
|
||||
0xdb71e91432b1a24a,0xc9e82cd9f69d6150,
|
||||
0x892731ac9faf056e,0xbe311c083a225cd2,
|
||||
0xab70fe17c79ac6ca,0x6dbd630a48aaf406,
|
||||
0xd64d3d9db981787d,0x92cbbccdad5b108,
|
||||
0x85f0468293f0eb4e,0x25bbf56008c58ea5,
|
||||
0xa76c582338ed2621,0xaf2af2b80af6f24e,
|
||||
0xd1476e2c07286faa,0x1af5af660db4aee1,
|
||||
0x82cca4db847945ca,0x50d98d9fc890ed4d,
|
||||
0xa37fce126597973c,0xe50ff107bab528a0,
|
||||
0xcc5fc196fefd7d0c,0x1e53ed49a96272c8,
|
||||
0xff77b1fcbebcdc4f,0x25e8e89c13bb0f7a,
|
||||
0x9faacf3df73609b1,0x77b191618c54e9ac,
|
||||
0xc795830d75038c1d,0xd59df5b9ef6a2417,
|
||||
0xf97ae3d0d2446f25,0x4b0573286b44ad1d,
|
||||
0x9becce62836ac577,0x4ee367f9430aec32,
|
||||
0xc2e801fb244576d5,0x229c41f793cda73f,
|
||||
0xf3a20279ed56d48a,0x6b43527578c1110f,
|
||||
0x9845418c345644d6,0x830a13896b78aaa9,
|
||||
0xbe5691ef416bd60c,0x23cc986bc656d553,
|
||||
0xedec366b11c6cb8f,0x2cbfbe86b7ec8aa8,
|
||||
0x94b3a202eb1c3f39,0x7bf7d71432f3d6a9,
|
||||
0xb9e08a83a5e34f07,0xdaf5ccd93fb0cc53,
|
||||
0xe858ad248f5c22c9,0xd1b3400f8f9cff68,
|
||||
0x91376c36d99995be,0x23100809b9c21fa1,
|
||||
0xb58547448ffffb2d,0xabd40a0c2832a78a,
|
||||
0xe2e69915b3fff9f9,0x16c90c8f323f516c,
|
||||
0x8dd01fad907ffc3b,0xae3da7d97f6792e3,
|
||||
0xb1442798f49ffb4a,0x99cd11cfdf41779c,
|
||||
0xdd95317f31c7fa1d,0x40405643d711d583,
|
||||
0x8a7d3eef7f1cfc52,0x482835ea666b2572,
|
||||
0xad1c8eab5ee43b66,0xda3243650005eecf,
|
||||
0xd863b256369d4a40,0x90bed43e40076a82,
|
||||
0x873e4f75e2224e68,0x5a7744a6e804a291,
|
||||
0xa90de3535aaae202,0x711515d0a205cb36,
|
||||
0xd3515c2831559a83,0xd5a5b44ca873e03,
|
||||
0x8412d9991ed58091,0xe858790afe9486c2,
|
||||
0xa5178fff668ae0b6,0x626e974dbe39a872,
|
||||
0xce5d73ff402d98e3,0xfb0a3d212dc8128f,
|
||||
0x80fa687f881c7f8e,0x7ce66634bc9d0b99,
|
||||
0xa139029f6a239f72,0x1c1fffc1ebc44e80,
|
||||
0xc987434744ac874e,0xa327ffb266b56220,
|
||||
0xfbe9141915d7a922,0x4bf1ff9f0062baa8,
|
||||
0x9d71ac8fada6c9b5,0x6f773fc3603db4a9,
|
||||
0xc4ce17b399107c22,0xcb550fb4384d21d3,
|
||||
0xf6019da07f549b2b,0x7e2a53a146606a48,
|
||||
0x99c102844f94e0fb,0x2eda7444cbfc426d,
|
||||
0xc0314325637a1939,0xfa911155fefb5308,
|
||||
0xf03d93eebc589f88,0x793555ab7eba27ca,
|
||||
0x96267c7535b763b5,0x4bc1558b2f3458de,
|
||||
0xbbb01b9283253ca2,0x9eb1aaedfb016f16,
|
||||
0xea9c227723ee8bcb,0x465e15a979c1cadc,
|
||||
0x92a1958a7675175f,0xbfacd89ec191ec9,
|
||||
0xb749faed14125d36,0xcef980ec671f667b,
|
||||
0xe51c79a85916f484,0x82b7e12780e7401a,
|
||||
0x8f31cc0937ae58d2,0xd1b2ecb8b0908810,
|
||||
0xb2fe3f0b8599ef07,0x861fa7e6dcb4aa15,
|
||||
0xdfbdcece67006ac9,0x67a791e093e1d49a,
|
||||
0x8bd6a141006042bd,0xe0c8bb2c5c6d24e0,
|
||||
0xaecc49914078536d,0x58fae9f773886e18,
|
||||
0xda7f5bf590966848,0xaf39a475506a899e,
|
||||
0x888f99797a5e012d,0x6d8406c952429603,
|
||||
0xaab37fd7d8f58178,0xc8e5087ba6d33b83,
|
||||
0xd5605fcdcf32e1d6,0xfb1e4a9a90880a64,
|
||||
0x855c3be0a17fcd26,0x5cf2eea09a55067f,
|
||||
0xa6b34ad8c9dfc06f,0xf42faa48c0ea481e,
|
||||
0xd0601d8efc57b08b,0xf13b94daf124da26,
|
||||
0x823c12795db6ce57,0x76c53d08d6b70858,
|
||||
0xa2cb1717b52481ed,0x54768c4b0c64ca6e,
|
||||
0xcb7ddcdda26da268,0xa9942f5dcf7dfd09,
|
||||
0xfe5d54150b090b02,0xd3f93b35435d7c4c,
|
||||
0x9efa548d26e5a6e1,0xc47bc5014a1a6daf,
|
||||
0xc6b8e9b0709f109a,0x359ab6419ca1091b,
|
||||
0xf867241c8cc6d4c0,0xc30163d203c94b62,
|
||||
0x9b407691d7fc44f8,0x79e0de63425dcf1d,
|
||||
0xc21094364dfb5636,0x985915fc12f542e4,
|
||||
0xf294b943e17a2bc4,0x3e6f5b7b17b2939d,
|
||||
0x979cf3ca6cec5b5a,0xa705992ceecf9c42,
|
||||
0xbd8430bd08277231,0x50c6ff782a838353,
|
||||
0xece53cec4a314ebd,0xa4f8bf5635246428,
|
||||
0x940f4613ae5ed136,0x871b7795e136be99,
|
||||
0xb913179899f68584,0x28e2557b59846e3f,
|
||||
0xe757dd7ec07426e5,0x331aeada2fe589cf,
|
||||
0x9096ea6f3848984f,0x3ff0d2c85def7621,
|
||||
0xb4bca50b065abe63,0xfed077a756b53a9,
|
||||
0xe1ebce4dc7f16dfb,0xd3e8495912c62894,
|
||||
0x8d3360f09cf6e4bd,0x64712dd7abbbd95c,
|
||||
0xb080392cc4349dec,0xbd8d794d96aacfb3,
|
||||
0xdca04777f541c567,0xecf0d7a0fc5583a0,
|
||||
0x89e42caaf9491b60,0xf41686c49db57244,
|
||||
0xac5d37d5b79b6239,0x311c2875c522ced5,
|
||||
0xd77485cb25823ac7,0x7d633293366b828b,
|
||||
0x86a8d39ef77164bc,0xae5dff9c02033197,
|
||||
0xa8530886b54dbdeb,0xd9f57f830283fdfc,
|
||||
0xd267caa862a12d66,0xd072df63c324fd7b,
|
||||
0x8380dea93da4bc60,0x4247cb9e59f71e6d,
|
||||
0xa46116538d0deb78,0x52d9be85f074e608,
|
||||
0xcd795be870516656,0x67902e276c921f8b,
|
||||
0x806bd9714632dff6,0xba1cd8a3db53b6,
|
||||
0xa086cfcd97bf97f3,0x80e8a40eccd228a4,
|
||||
0xc8a883c0fdaf7df0,0x6122cd128006b2cd,
|
||||
0xfad2a4b13d1b5d6c,0x796b805720085f81,
|
||||
0x9cc3a6eec6311a63,0xcbe3303674053bb0,
|
||||
0xc3f490aa77bd60fc,0xbedbfc4411068a9c,
|
||||
0xf4f1b4d515acb93b,0xee92fb5515482d44,
|
||||
0x991711052d8bf3c5,0x751bdd152d4d1c4a,
|
||||
0xbf5cd54678eef0b6,0xd262d45a78a0635d,
|
||||
0xef340a98172aace4,0x86fb897116c87c34,
|
||||
0x9580869f0e7aac0e,0xd45d35e6ae3d4da0,
|
||||
0xbae0a846d2195712,0x8974836059cca109,
|
||||
0xe998d258869facd7,0x2bd1a438703fc94b,
|
||||
0x91ff83775423cc06,0x7b6306a34627ddcf,
|
||||
0xb67f6455292cbf08,0x1a3bc84c17b1d542,
|
||||
0xe41f3d6a7377eeca,0x20caba5f1d9e4a93,
|
||||
0x8e938662882af53e,0x547eb47b7282ee9c,
|
||||
0xb23867fb2a35b28d,0xe99e619a4f23aa43,
|
||||
0xdec681f9f4c31f31,0x6405fa00e2ec94d4,
|
||||
0x8b3c113c38f9f37e,0xde83bc408dd3dd04,
|
||||
0xae0b158b4738705e,0x9624ab50b148d445,
|
||||
0xd98ddaee19068c76,0x3badd624dd9b0957,
|
||||
0x87f8a8d4cfa417c9,0xe54ca5d70a80e5d6,
|
||||
0xa9f6d30a038d1dbc,0x5e9fcf4ccd211f4c,
|
||||
0xd47487cc8470652b,0x7647c3200069671f,
|
||||
0x84c8d4dfd2c63f3b,0x29ecd9f40041e073,
|
||||
0xa5fb0a17c777cf09,0xf468107100525890,
|
||||
0xcf79cc9db955c2cc,0x7182148d4066eeb4,
|
||||
0x81ac1fe293d599bf,0xc6f14cd848405530,
|
||||
0xa21727db38cb002f,0xb8ada00e5a506a7c,
|
||||
0xca9cf1d206fdc03b,0xa6d90811f0e4851c,
|
||||
0xfd442e4688bd304a,0x908f4a166d1da663,
|
||||
0x9e4a9cec15763e2e,0x9a598e4e043287fe,
|
||||
0xc5dd44271ad3cdba,0x40eff1e1853f29fd,
|
||||
0xf7549530e188c128,0xd12bee59e68ef47c,
|
||||
0x9a94dd3e8cf578b9,0x82bb74f8301958ce,
|
||||
0xc13a148e3032d6e7,0xe36a52363c1faf01,
|
||||
0xf18899b1bc3f8ca1,0xdc44e6c3cb279ac1,
|
||||
0x96f5600f15a7b7e5,0x29ab103a5ef8c0b9,
|
||||
0xbcb2b812db11a5de,0x7415d448f6b6f0e7,
|
||||
0xebdf661791d60f56,0x111b495b3464ad21,
|
||||
0x936b9fcebb25c995,0xcab10dd900beec34,
|
||||
0xb84687c269ef3bfb,0x3d5d514f40eea742,
|
||||
0xe65829b3046b0afa,0xcb4a5a3112a5112,
|
||||
0x8ff71a0fe2c2e6dc,0x47f0e785eaba72ab,
|
||||
0xb3f4e093db73a093,0x59ed216765690f56,
|
||||
0xe0f218b8d25088b8,0x306869c13ec3532c,
|
||||
0x8c974f7383725573,0x1e414218c73a13fb,
|
||||
0xafbd2350644eeacf,0xe5d1929ef90898fa,
|
||||
0xdbac6c247d62a583,0xdf45f746b74abf39,
|
||||
0x894bc396ce5da772,0x6b8bba8c328eb783,
|
||||
0xab9eb47c81f5114f,0x66ea92f3f326564,
|
||||
0xd686619ba27255a2,0xc80a537b0efefebd,
|
||||
0x8613fd0145877585,0xbd06742ce95f5f36,
|
||||
0xa798fc4196e952e7,0x2c48113823b73704,
|
||||
0xd17f3b51fca3a7a0,0xf75a15862ca504c5,
|
||||
0x82ef85133de648c4,0x9a984d73dbe722fb,
|
||||
0xa3ab66580d5fdaf5,0xc13e60d0d2e0ebba,
|
||||
0xcc963fee10b7d1b3,0x318df905079926a8,
|
||||
0xffbbcfe994e5c61f,0xfdf17746497f7052,
|
||||
0x9fd561f1fd0f9bd3,0xfeb6ea8bedefa633,
|
||||
0xc7caba6e7c5382c8,0xfe64a52ee96b8fc0,
|
||||
0xf9bd690a1b68637b,0x3dfdce7aa3c673b0,
|
||||
0x9c1661a651213e2d,0x6bea10ca65c084e,
|
||||
0xc31bfa0fe5698db8,0x486e494fcff30a62,
|
||||
0xf3e2f893dec3f126,0x5a89dba3c3efccfa,
|
||||
0x986ddb5c6b3a76b7,0xf89629465a75e01c,
|
||||
0xbe89523386091465,0xf6bbb397f1135823,
|
||||
0xee2ba6c0678b597f,0x746aa07ded582e2c,
|
||||
0x94db483840b717ef,0xa8c2a44eb4571cdc,
|
||||
0xba121a4650e4ddeb,0x92f34d62616ce413,
|
||||
0xe896a0d7e51e1566,0x77b020baf9c81d17,
|
||||
0x915e2486ef32cd60,0xace1474dc1d122e,
|
||||
0xb5b5ada8aaff80b8,0xd819992132456ba,
|
||||
0xe3231912d5bf60e6,0x10e1fff697ed6c69,
|
||||
0x8df5efabc5979c8f,0xca8d3ffa1ef463c1,
|
||||
0xb1736b96b6fd83b3,0xbd308ff8a6b17cb2,
|
||||
0xddd0467c64bce4a0,0xac7cb3f6d05ddbde,
|
||||
0x8aa22c0dbef60ee4,0x6bcdf07a423aa96b,
|
||||
0xad4ab7112eb3929d,0x86c16c98d2c953c6,
|
||||
0xd89d64d57a607744,0xe871c7bf077ba8b7,
|
||||
0x87625f056c7c4a8b,0x11471cd764ad4972,
|
||||
0xa93af6c6c79b5d2d,0xd598e40d3dd89bcf,
|
||||
0xd389b47879823479,0x4aff1d108d4ec2c3,
|
||||
0x843610cb4bf160cb,0xcedf722a585139ba,
|
||||
0xa54394fe1eedb8fe,0xc2974eb4ee658828,
|
||||
0xce947a3da6a9273e,0x733d226229feea32,
|
||||
0x811ccc668829b887,0x806357d5a3f525f,
|
||||
0xa163ff802a3426a8,0xca07c2dcb0cf26f7,
|
||||
0xc9bcff6034c13052,0xfc89b393dd02f0b5,
|
||||
0xfc2c3f3841f17c67,0xbbac2078d443ace2,
|
||||
0x9d9ba7832936edc0,0xd54b944b84aa4c0d,
|
||||
0xc5029163f384a931,0xa9e795e65d4df11,
|
||||
0xf64335bcf065d37d,0x4d4617b5ff4a16d5,
|
||||
0x99ea0196163fa42e,0x504bced1bf8e4e45,
|
||||
0xc06481fb9bcf8d39,0xe45ec2862f71e1d6,
|
||||
0xf07da27a82c37088,0x5d767327bb4e5a4c,
|
||||
0x964e858c91ba2655,0x3a6a07f8d510f86f,
|
||||
0xbbe226efb628afea,0x890489f70a55368b,
|
||||
0xeadab0aba3b2dbe5,0x2b45ac74ccea842e,
|
||||
0x92c8ae6b464fc96f,0x3b0b8bc90012929d,
|
||||
0xb77ada0617e3bbcb,0x9ce6ebb40173744,
|
||||
0xe55990879ddcaabd,0xcc420a6a101d0515,
|
||||
0x8f57fa54c2a9eab6,0x9fa946824a12232d,
|
||||
0xb32df8e9f3546564,0x47939822dc96abf9,
|
||||
0xdff9772470297ebd,0x59787e2b93bc56f7,
|
||||
0x8bfbea76c619ef36,0x57eb4edb3c55b65a,
|
||||
0xaefae51477a06b03,0xede622920b6b23f1,
|
||||
0xdab99e59958885c4,0xe95fab368e45eced,
|
||||
0x88b402f7fd75539b,0x11dbcb0218ebb414,
|
||||
0xaae103b5fcd2a881,0xd652bdc29f26a119,
|
||||
0xd59944a37c0752a2,0x4be76d3346f0495f,
|
||||
0x857fcae62d8493a5,0x6f70a4400c562ddb,
|
||||
0xa6dfbd9fb8e5b88e,0xcb4ccd500f6bb952,
|
||||
0xd097ad07a71f26b2,0x7e2000a41346a7a7,
|
||||
0x825ecc24c873782f,0x8ed400668c0c28c8,
|
||||
0xa2f67f2dfa90563b,0x728900802f0f32fa,
|
||||
0xcbb41ef979346bca,0x4f2b40a03ad2ffb9,
|
||||
0xfea126b7d78186bc,0xe2f610c84987bfa8,
|
||||
0x9f24b832e6b0f436,0xdd9ca7d2df4d7c9,
|
||||
0xc6ede63fa05d3143,0x91503d1c79720dbb,
|
||||
0xf8a95fcf88747d94,0x75a44c6397ce912a,
|
||||
0x9b69dbe1b548ce7c,0xc986afbe3ee11aba,
|
||||
0xc24452da229b021b,0xfbe85badce996168,
|
||||
0xf2d56790ab41c2a2,0xfae27299423fb9c3,
|
||||
0x97c560ba6b0919a5,0xdccd879fc967d41a,
|
||||
0xbdb6b8e905cb600f,0x5400e987bbc1c920,
|
||||
0xed246723473e3813,0x290123e9aab23b68,
|
||||
0x9436c0760c86e30b,0xf9a0b6720aaf6521,
|
||||
0xb94470938fa89bce,0xf808e40e8d5b3e69,
|
||||
0xe7958cb87392c2c2,0xb60b1d1230b20e04,
|
||||
0x90bd77f3483bb9b9,0xb1c6f22b5e6f48c2,
|
||||
0xb4ecd5f01a4aa828,0x1e38aeb6360b1af3,
|
||||
0xe2280b6c20dd5232,0x25c6da63c38de1b0,
|
||||
0x8d590723948a535f,0x579c487e5a38ad0e,
|
||||
0xb0af48ec79ace837,0x2d835a9df0c6d851,
|
||||
0xdcdb1b2798182244,0xf8e431456cf88e65,
|
||||
0x8a08f0f8bf0f156b,0x1b8e9ecb641b58ff,
|
||||
0xac8b2d36eed2dac5,0xe272467e3d222f3f,
|
||||
0xd7adf884aa879177,0x5b0ed81dcc6abb0f,
|
||||
0x86ccbb52ea94baea,0x98e947129fc2b4e9,
|
||||
0xa87fea27a539e9a5,0x3f2398d747b36224,
|
||||
0xd29fe4b18e88640e,0x8eec7f0d19a03aad,
|
||||
0x83a3eeeef9153e89,0x1953cf68300424ac,
|
||||
0xa48ceaaab75a8e2b,0x5fa8c3423c052dd7,
|
||||
0xcdb02555653131b6,0x3792f412cb06794d,
|
||||
0x808e17555f3ebf11,0xe2bbd88bbee40bd0,
|
||||
0xa0b19d2ab70e6ed6,0x5b6aceaeae9d0ec4,
|
||||
0xc8de047564d20a8b,0xf245825a5a445275,
|
||||
0xfb158592be068d2e,0xeed6e2f0f0d56712,
|
||||
0x9ced737bb6c4183d,0x55464dd69685606b,
|
||||
0xc428d05aa4751e4c,0xaa97e14c3c26b886,
|
||||
0xf53304714d9265df,0xd53dd99f4b3066a8,
|
||||
0x993fe2c6d07b7fab,0xe546a8038efe4029,
|
||||
0xbf8fdb78849a5f96,0xde98520472bdd033,
|
||||
0xef73d256a5c0f77c,0x963e66858f6d4440,
|
||||
0x95a8637627989aad,0xdde7001379a44aa8,
|
||||
0xbb127c53b17ec159,0x5560c018580d5d52,
|
||||
0xe9d71b689dde71af,0xaab8f01e6e10b4a6,
|
||||
0x9226712162ab070d,0xcab3961304ca70e8,
|
||||
0xb6b00d69bb55c8d1,0x3d607b97c5fd0d22,
|
||||
0xe45c10c42a2b3b05,0x8cb89a7db77c506a,
|
||||
0x8eb98a7a9a5b04e3,0x77f3608e92adb242,
|
||||
0xb267ed1940f1c61c,0x55f038b237591ed3,
|
||||
0xdf01e85f912e37a3,0x6b6c46dec52f6688,
|
||||
0x8b61313bbabce2c6,0x2323ac4b3b3da015,
|
||||
0xae397d8aa96c1b77,0xabec975e0a0d081a,
|
||||
0xd9c7dced53c72255,0x96e7bd358c904a21,
|
||||
0x881cea14545c7575,0x7e50d64177da2e54,
|
||||
0xaa242499697392d2,0xdde50bd1d5d0b9e9,
|
||||
0xd4ad2dbfc3d07787,0x955e4ec64b44e864,
|
||||
0x84ec3c97da624ab4,0xbd5af13bef0b113e,
|
||||
0xa6274bbdd0fadd61,0xecb1ad8aeacdd58e,
|
||||
0xcfb11ead453994ba,0x67de18eda5814af2,
|
||||
0x81ceb32c4b43fcf4,0x80eacf948770ced7,
|
||||
0xa2425ff75e14fc31,0xa1258379a94d028d,
|
||||
0xcad2f7f5359a3b3e,0x96ee45813a04330,
|
||||
0xfd87b5f28300ca0d,0x8bca9d6e188853fc,
|
||||
0x9e74d1b791e07e48,0x775ea264cf55347e,
|
||||
0xc612062576589dda,0x95364afe032a819e,
|
||||
0xf79687aed3eec551,0x3a83ddbd83f52205,
|
||||
0x9abe14cd44753b52,0xc4926a9672793543,
|
||||
0xc16d9a0095928a27,0x75b7053c0f178294,
|
||||
0xf1c90080baf72cb1,0x5324c68b12dd6339,
|
||||
0x971da05074da7bee,0xd3f6fc16ebca5e04,
|
||||
0xbce5086492111aea,0x88f4bb1ca6bcf585,
|
||||
0xec1e4a7db69561a5,0x2b31e9e3d06c32e6,
|
||||
0x9392ee8e921d5d07,0x3aff322e62439fd0,
|
||||
0xb877aa3236a4b449,0x9befeb9fad487c3,
|
||||
0xe69594bec44de15b,0x4c2ebe687989a9b4,
|
||||
0x901d7cf73ab0acd9,0xf9d37014bf60a11,
|
||||
0xb424dc35095cd80f,0x538484c19ef38c95,
|
||||
0xe12e13424bb40e13,0x2865a5f206b06fba,
|
||||
0x8cbccc096f5088cb,0xf93f87b7442e45d4,
|
||||
0xafebff0bcb24aafe,0xf78f69a51539d749,
|
||||
0xdbe6fecebdedd5be,0xb573440e5a884d1c,
|
||||
0x89705f4136b4a597,0x31680a88f8953031,
|
||||
0xabcc77118461cefc,0xfdc20d2b36ba7c3e,
|
||||
0xd6bf94d5e57a42bc,0x3d32907604691b4d,
|
||||
0x8637bd05af6c69b5,0xa63f9a49c2c1b110,
|
||||
0xa7c5ac471b478423,0xfcf80dc33721d54,
|
||||
0xd1b71758e219652b,0xd3c36113404ea4a9,
|
||||
0x83126e978d4fdf3b,0x645a1cac083126ea,
|
||||
0xa3d70a3d70a3d70a,0x3d70a3d70a3d70a4,
|
||||
0xcccccccccccccccc,0xcccccccccccccccd,
|
||||
0x8000000000000000,0x0,
|
||||
0xa000000000000000,0x0,
|
||||
0xc800000000000000,0x0,
|
||||
0xfa00000000000000,0x0,
|
||||
0x9c40000000000000,0x0,
|
||||
0xc350000000000000,0x0,
|
||||
0xf424000000000000,0x0,
|
||||
0x9896800000000000,0x0,
|
||||
0xbebc200000000000,0x0,
|
||||
0xee6b280000000000,0x0,
|
||||
0x9502f90000000000,0x0,
|
||||
0xba43b74000000000,0x0,
|
||||
0xe8d4a51000000000,0x0,
|
||||
0x9184e72a00000000,0x0,
|
||||
0xb5e620f480000000,0x0,
|
||||
0xe35fa931a0000000,0x0,
|
||||
0x8e1bc9bf04000000,0x0,
|
||||
0xb1a2bc2ec5000000,0x0,
|
||||
0xde0b6b3a76400000,0x0,
|
||||
0x8ac7230489e80000,0x0,
|
||||
0xad78ebc5ac620000,0x0,
|
||||
0xd8d726b7177a8000,0x0,
|
||||
0x878678326eac9000,0x0,
|
||||
0xa968163f0a57b400,0x0,
|
||||
0xd3c21bcecceda100,0x0,
|
||||
0x84595161401484a0,0x0,
|
||||
0xa56fa5b99019a5c8,0x0,
|
||||
0xcecb8f27f4200f3a,0x0,
|
||||
0x813f3978f8940984,0x4000000000000000,
|
||||
0xa18f07d736b90be5,0x5000000000000000,
|
||||
0xc9f2c9cd04674ede,0xa400000000000000,
|
||||
0xfc6f7c4045812296,0x4d00000000000000,
|
||||
0x9dc5ada82b70b59d,0xf020000000000000,
|
||||
0xc5371912364ce305,0x6c28000000000000,
|
||||
0xf684df56c3e01bc6,0xc732000000000000,
|
||||
0x9a130b963a6c115c,0x3c7f400000000000,
|
||||
0xc097ce7bc90715b3,0x4b9f100000000000,
|
||||
0xf0bdc21abb48db20,0x1e86d40000000000,
|
||||
0x96769950b50d88f4,0x1314448000000000,
|
||||
0xbc143fa4e250eb31,0x17d955a000000000,
|
||||
0xeb194f8e1ae525fd,0x5dcfab0800000000,
|
||||
0x92efd1b8d0cf37be,0x5aa1cae500000000,
|
||||
0xb7abc627050305ad,0xf14a3d9e40000000,
|
||||
0xe596b7b0c643c719,0x6d9ccd05d0000000,
|
||||
0x8f7e32ce7bea5c6f,0xe4820023a2000000,
|
||||
0xb35dbf821ae4f38b,0xdda2802c8a800000,
|
||||
0xe0352f62a19e306e,0xd50b2037ad200000,
|
||||
0x8c213d9da502de45,0x4526f422cc340000,
|
||||
0xaf298d050e4395d6,0x9670b12b7f410000,
|
||||
0xdaf3f04651d47b4c,0x3c0cdd765f114000,
|
||||
0x88d8762bf324cd0f,0xa5880a69fb6ac800,
|
||||
0xab0e93b6efee0053,0x8eea0d047a457a00,
|
||||
0xd5d238a4abe98068,0x72a4904598d6d880,
|
||||
0x85a36366eb71f041,0x47a6da2b7f864750,
|
||||
0xa70c3c40a64e6c51,0x999090b65f67d924,
|
||||
0xd0cf4b50cfe20765,0xfff4b4e3f741cf6d,
|
||||
0x82818f1281ed449f,0xbff8f10e7a8921a4,
|
||||
0xa321f2d7226895c7,0xaff72d52192b6a0d,
|
||||
0xcbea6f8ceb02bb39,0x9bf4f8a69f764490,
|
||||
0xfee50b7025c36a08,0x2f236d04753d5b4,
|
||||
0x9f4f2726179a2245,0x1d762422c946590,
|
||||
0xc722f0ef9d80aad6,0x424d3ad2b7b97ef5,
|
||||
0xf8ebad2b84e0d58b,0xd2e0898765a7deb2,
|
||||
0x9b934c3b330c8577,0x63cc55f49f88eb2f,
|
||||
0xc2781f49ffcfa6d5,0x3cbf6b71c76b25fb,
|
||||
0xf316271c7fc3908a,0x8bef464e3945ef7a,
|
||||
0x97edd871cfda3a56,0x97758bf0e3cbb5ac,
|
||||
0xbde94e8e43d0c8ec,0x3d52eeed1cbea317,
|
||||
0xed63a231d4c4fb27,0x4ca7aaa863ee4bdd,
|
||||
0x945e455f24fb1cf8,0x8fe8caa93e74ef6a,
|
||||
0xb975d6b6ee39e436,0xb3e2fd538e122b44,
|
||||
0xe7d34c64a9c85d44,0x60dbbca87196b616,
|
||||
0x90e40fbeea1d3a4a,0xbc8955e946fe31cd,
|
||||
0xb51d13aea4a488dd,0x6babab6398bdbe41,
|
||||
0xe264589a4dcdab14,0xc696963c7eed2dd1,
|
||||
0x8d7eb76070a08aec,0xfc1e1de5cf543ca2,
|
||||
0xb0de65388cc8ada8,0x3b25a55f43294bcb,
|
||||
0xdd15fe86affad912,0x49ef0eb713f39ebe,
|
||||
0x8a2dbf142dfcc7ab,0x6e3569326c784337,
|
||||
0xacb92ed9397bf996,0x49c2c37f07965404,
|
||||
0xd7e77a8f87daf7fb,0xdc33745ec97be906,
|
||||
0x86f0ac99b4e8dafd,0x69a028bb3ded71a3,
|
||||
0xa8acd7c0222311bc,0xc40832ea0d68ce0c,
|
||||
0xd2d80db02aabd62b,0xf50a3fa490c30190,
|
||||
0x83c7088e1aab65db,0x792667c6da79e0fa,
|
||||
0xa4b8cab1a1563f52,0x577001b891185938,
|
||||
0xcde6fd5e09abcf26,0xed4c0226b55e6f86,
|
||||
0x80b05e5ac60b6178,0x544f8158315b05b4,
|
||||
0xa0dc75f1778e39d6,0x696361ae3db1c721,
|
||||
0xc913936dd571c84c,0x3bc3a19cd1e38e9,
|
||||
0xfb5878494ace3a5f,0x4ab48a04065c723,
|
||||
0x9d174b2dcec0e47b,0x62eb0d64283f9c76,
|
||||
0xc45d1df942711d9a,0x3ba5d0bd324f8394,
|
||||
0xf5746577930d6500,0xca8f44ec7ee36479,
|
||||
0x9968bf6abbe85f20,0x7e998b13cf4e1ecb,
|
||||
0xbfc2ef456ae276e8,0x9e3fedd8c321a67e,
|
||||
0xefb3ab16c59b14a2,0xc5cfe94ef3ea101e,
|
||||
0x95d04aee3b80ece5,0xbba1f1d158724a12,
|
||||
0xbb445da9ca61281f,0x2a8a6e45ae8edc97,
|
||||
0xea1575143cf97226,0xf52d09d71a3293bd,
|
||||
0x924d692ca61be758,0x593c2626705f9c56,
|
||||
0xb6e0c377cfa2e12e,0x6f8b2fb00c77836c,
|
||||
0xe498f455c38b997a,0xb6dfb9c0f956447,
|
||||
0x8edf98b59a373fec,0x4724bd4189bd5eac,
|
||||
0xb2977ee300c50fe7,0x58edec91ec2cb657,
|
||||
0xdf3d5e9bc0f653e1,0x2f2967b66737e3ed,
|
||||
0x8b865b215899f46c,0xbd79e0d20082ee74,
|
||||
0xae67f1e9aec07187,0xecd8590680a3aa11,
|
||||
0xda01ee641a708de9,0xe80e6f4820cc9495,
|
||||
0x884134fe908658b2,0x3109058d147fdcdd,
|
||||
0xaa51823e34a7eede,0xbd4b46f0599fd415,
|
||||
0xd4e5e2cdc1d1ea96,0x6c9e18ac7007c91a,
|
||||
0x850fadc09923329e,0x3e2cf6bc604ddb0,
|
||||
0xa6539930bf6bff45,0x84db8346b786151c,
|
||||
0xcfe87f7cef46ff16,0xe612641865679a63,
|
||||
0x81f14fae158c5f6e,0x4fcb7e8f3f60c07e,
|
||||
0xa26da3999aef7749,0xe3be5e330f38f09d,
|
||||
0xcb090c8001ab551c,0x5cadf5bfd3072cc5,
|
||||
0xfdcb4fa002162a63,0x73d9732fc7c8f7f6,
|
||||
0x9e9f11c4014dda7e,0x2867e7fddcdd9afa,
|
||||
0xc646d63501a1511d,0xb281e1fd541501b8,
|
||||
0xf7d88bc24209a565,0x1f225a7ca91a4226,
|
||||
0x9ae757596946075f,0x3375788de9b06958,
|
||||
0xc1a12d2fc3978937,0x52d6b1641c83ae,
|
||||
0xf209787bb47d6b84,0xc0678c5dbd23a49a,
|
||||
0x9745eb4d50ce6332,0xf840b7ba963646e0,
|
||||
0xbd176620a501fbff,0xb650e5a93bc3d898,
|
||||
0xec5d3fa8ce427aff,0xa3e51f138ab4cebe,
|
||||
0x93ba47c980e98cdf,0xc66f336c36b10137,
|
||||
0xb8a8d9bbe123f017,0xb80b0047445d4184,
|
||||
0xe6d3102ad96cec1d,0xa60dc059157491e5,
|
||||
0x9043ea1ac7e41392,0x87c89837ad68db2f,
|
||||
0xb454e4a179dd1877,0x29babe4598c311fb,
|
||||
0xe16a1dc9d8545e94,0xf4296dd6fef3d67a,
|
||||
0x8ce2529e2734bb1d,0x1899e4a65f58660c,
|
||||
0xb01ae745b101e9e4,0x5ec05dcff72e7f8f,
|
||||
0xdc21a1171d42645d,0x76707543f4fa1f73,
|
||||
0x899504ae72497eba,0x6a06494a791c53a8,
|
||||
0xabfa45da0edbde69,0x487db9d17636892,
|
||||
0xd6f8d7509292d603,0x45a9d2845d3c42b6,
|
||||
0x865b86925b9bc5c2,0xb8a2392ba45a9b2,
|
||||
0xa7f26836f282b732,0x8e6cac7768d7141e,
|
||||
0xd1ef0244af2364ff,0x3207d795430cd926,
|
||||
0x8335616aed761f1f,0x7f44e6bd49e807b8,
|
||||
0xa402b9c5a8d3a6e7,0x5f16206c9c6209a6,
|
||||
0xcd036837130890a1,0x36dba887c37a8c0f,
|
||||
0x802221226be55a64,0xc2494954da2c9789,
|
||||
0xa02aa96b06deb0fd,0xf2db9baa10b7bd6c,
|
||||
0xc83553c5c8965d3d,0x6f92829494e5acc7,
|
||||
0xfa42a8b73abbf48c,0xcb772339ba1f17f9,
|
||||
0x9c69a97284b578d7,0xff2a760414536efb,
|
||||
0xc38413cf25e2d70d,0xfef5138519684aba,
|
||||
0xf46518c2ef5b8cd1,0x7eb258665fc25d69,
|
||||
0x98bf2f79d5993802,0xef2f773ffbd97a61,
|
||||
0xbeeefb584aff8603,0xaafb550ffacfd8fa,
|
||||
0xeeaaba2e5dbf6784,0x95ba2a53f983cf38,
|
||||
0x952ab45cfa97a0b2,0xdd945a747bf26183,
|
||||
0xba756174393d88df,0x94f971119aeef9e4,
|
||||
0xe912b9d1478ceb17,0x7a37cd5601aab85d,
|
||||
0x91abb422ccb812ee,0xac62e055c10ab33a,
|
||||
0xb616a12b7fe617aa,0x577b986b314d6009,
|
||||
0xe39c49765fdf9d94,0xed5a7e85fda0b80b,
|
||||
0x8e41ade9fbebc27d,0x14588f13be847307,
|
||||
0xb1d219647ae6b31c,0x596eb2d8ae258fc8,
|
||||
0xde469fbd99a05fe3,0x6fca5f8ed9aef3bb,
|
||||
0x8aec23d680043bee,0x25de7bb9480d5854,
|
||||
0xada72ccc20054ae9,0xaf561aa79a10ae6a,
|
||||
0xd910f7ff28069da4,0x1b2ba1518094da04,
|
||||
0x87aa9aff79042286,0x90fb44d2f05d0842,
|
||||
0xa99541bf57452b28,0x353a1607ac744a53,
|
||||
0xd3fa922f2d1675f2,0x42889b8997915ce8,
|
||||
0x847c9b5d7c2e09b7,0x69956135febada11,
|
||||
0xa59bc234db398c25,0x43fab9837e699095,
|
||||
0xcf02b2c21207ef2e,0x94f967e45e03f4bb,
|
||||
0x8161afb94b44f57d,0x1d1be0eebac278f5,
|
||||
0xa1ba1ba79e1632dc,0x6462d92a69731732,
|
||||
0xca28a291859bbf93,0x7d7b8f7503cfdcfe,
|
||||
0xfcb2cb35e702af78,0x5cda735244c3d43e,
|
||||
0x9defbf01b061adab,0x3a0888136afa64a7,
|
||||
0xc56baec21c7a1916,0x88aaa1845b8fdd0,
|
||||
0xf6c69a72a3989f5b,0x8aad549e57273d45,
|
||||
0x9a3c2087a63f6399,0x36ac54e2f678864b,
|
||||
0xc0cb28a98fcf3c7f,0x84576a1bb416a7dd,
|
||||
0xf0fdf2d3f3c30b9f,0x656d44a2a11c51d5,
|
||||
0x969eb7c47859e743,0x9f644ae5a4b1b325,
|
||||
0xbc4665b596706114,0x873d5d9f0dde1fee,
|
||||
0xeb57ff22fc0c7959,0xa90cb506d155a7ea,
|
||||
0x9316ff75dd87cbd8,0x9a7f12442d588f2,
|
||||
0xb7dcbf5354e9bece,0xc11ed6d538aeb2f,
|
||||
0xe5d3ef282a242e81,0x8f1668c8a86da5fa,
|
||||
0x8fa475791a569d10,0xf96e017d694487bc,
|
||||
0xb38d92d760ec4455,0x37c981dcc395a9ac,
|
||||
0xe070f78d3927556a,0x85bbe253f47b1417,
|
||||
0x8c469ab843b89562,0x93956d7478ccec8e,
|
||||
0xaf58416654a6babb,0x387ac8d1970027b2,
|
||||
0xdb2e51bfe9d0696a,0x6997b05fcc0319e,
|
||||
0x88fcf317f22241e2,0x441fece3bdf81f03,
|
||||
0xab3c2fddeeaad25a,0xd527e81cad7626c3,
|
||||
0xd60b3bd56a5586f1,0x8a71e223d8d3b074,
|
||||
0x85c7056562757456,0xf6872d5667844e49,
|
||||
0xa738c6bebb12d16c,0xb428f8ac016561db,
|
||||
0xd106f86e69d785c7,0xe13336d701beba52,
|
||||
0x82a45b450226b39c,0xecc0024661173473,
|
||||
0xa34d721642b06084,0x27f002d7f95d0190,
|
||||
0xcc20ce9bd35c78a5,0x31ec038df7b441f4,
|
||||
0xff290242c83396ce,0x7e67047175a15271,
|
||||
0x9f79a169bd203e41,0xf0062c6e984d386,
|
||||
0xc75809c42c684dd1,0x52c07b78a3e60868,
|
||||
0xf92e0c3537826145,0xa7709a56ccdf8a82,
|
||||
0x9bbcc7a142b17ccb,0x88a66076400bb691,
|
||||
0xc2abf989935ddbfe,0x6acff893d00ea435,
|
||||
0xf356f7ebf83552fe,0x583f6b8c4124d43,
|
||||
0x98165af37b2153de,0xc3727a337a8b704a,
|
||||
0xbe1bf1b059e9a8d6,0x744f18c0592e4c5c,
|
||||
0xeda2ee1c7064130c,0x1162def06f79df73,
|
||||
0x9485d4d1c63e8be7,0x8addcb5645ac2ba8,
|
||||
0xb9a74a0637ce2ee1,0x6d953e2bd7173692,
|
||||
0xe8111c87c5c1ba99,0xc8fa8db6ccdd0437,
|
||||
0x910ab1d4db9914a0,0x1d9c9892400a22a2,
|
||||
0xb54d5e4a127f59c8,0x2503beb6d00cab4b,
|
||||
0xe2a0b5dc971f303a,0x2e44ae64840fd61d,
|
||||
0x8da471a9de737e24,0x5ceaecfed289e5d2,
|
||||
0xb10d8e1456105dad,0x7425a83e872c5f47,
|
||||
0xdd50f1996b947518,0xd12f124e28f77719,
|
||||
0x8a5296ffe33cc92f,0x82bd6b70d99aaa6f,
|
||||
0xace73cbfdc0bfb7b,0x636cc64d1001550b,
|
||||
0xd8210befd30efa5a,0x3c47f7e05401aa4e,
|
||||
0x8714a775e3e95c78,0x65acfaec34810a71,
|
||||
0xa8d9d1535ce3b396,0x7f1839a741a14d0d,
|
||||
0xd31045a8341ca07c,0x1ede48111209a050,
|
||||
0x83ea2b892091e44d,0x934aed0aab460432,
|
||||
0xa4e4b66b68b65d60,0xf81da84d5617853f,
|
||||
0xce1de40642e3f4b9,0x36251260ab9d668e,
|
||||
0x80d2ae83e9ce78f3,0xc1d72b7c6b426019,
|
||||
0xa1075a24e4421730,0xb24cf65b8612f81f,
|
||||
0xc94930ae1d529cfc,0xdee033f26797b627,
|
||||
0xfb9b7cd9a4a7443c,0x169840ef017da3b1,
|
||||
0x9d412e0806e88aa5,0x8e1f289560ee864e,
|
||||
0xc491798a08a2ad4e,0xf1a6f2bab92a27e2,
|
||||
0xf5b5d7ec8acb58a2,0xae10af696774b1db,
|
||||
0x9991a6f3d6bf1765,0xacca6da1e0a8ef29,
|
||||
0xbff610b0cc6edd3f,0x17fd090a58d32af3,
|
||||
0xeff394dcff8a948e,0xddfc4b4cef07f5b0,
|
||||
0x95f83d0a1fb69cd9,0x4abdaf101564f98e,
|
||||
0xbb764c4ca7a4440f,0x9d6d1ad41abe37f1,
|
||||
0xea53df5fd18d5513,0x84c86189216dc5ed,
|
||||
0x92746b9be2f8552c,0x32fd3cf5b4e49bb4,
|
||||
0xb7118682dbb66a77,0x3fbc8c33221dc2a1,
|
||||
0xe4d5e82392a40515,0xfabaf3feaa5334a,
|
||||
0x8f05b1163ba6832d,0x29cb4d87f2a7400e,
|
||||
0xb2c71d5bca9023f8,0x743e20e9ef511012,
|
||||
0xdf78e4b2bd342cf6,0x914da9246b255416,
|
||||
0x8bab8eefb6409c1a,0x1ad089b6c2f7548e,
|
||||
0xae9672aba3d0c320,0xa184ac2473b529b1,
|
||||
0xda3c0f568cc4f3e8,0xc9e5d72d90a2741e,
|
||||
0x8865899617fb1871,0x7e2fa67c7a658892,
|
||||
0xaa7eebfb9df9de8d,0xddbb901b98feeab7,
|
||||
0xd51ea6fa85785631,0x552a74227f3ea565,
|
||||
0x8533285c936b35de,0xd53a88958f87275f,
|
||||
0xa67ff273b8460356,0x8a892abaf368f137,
|
||||
0xd01fef10a657842c,0x2d2b7569b0432d85,
|
||||
0x8213f56a67f6b29b,0x9c3b29620e29fc73,
|
||||
0xa298f2c501f45f42,0x8349f3ba91b47b8f,
|
||||
0xcb3f2f7642717713,0x241c70a936219a73,
|
||||
0xfe0efb53d30dd4d7,0xed238cd383aa0110,
|
||||
0x9ec95d1463e8a506,0xf4363804324a40aa,
|
||||
0xc67bb4597ce2ce48,0xb143c6053edcd0d5,
|
||||
0xf81aa16fdc1b81da,0xdd94b7868e94050a,
|
||||
0x9b10a4e5e9913128,0xca7cf2b4191c8326,
|
||||
0xc1d4ce1f63f57d72,0xfd1c2f611f63a3f0,
|
||||
0xf24a01a73cf2dccf,0xbc633b39673c8cec,
|
||||
0x976e41088617ca01,0xd5be0503e085d813,
|
||||
0xbd49d14aa79dbc82,0x4b2d8644d8a74e18,
|
||||
0xec9c459d51852ba2,0xddf8e7d60ed1219e,
|
||||
0x93e1ab8252f33b45,0xcabb90e5c942b503,
|
||||
0xb8da1662e7b00a17,0x3d6a751f3b936243,
|
||||
0xe7109bfba19c0c9d,0xcc512670a783ad4,
|
||||
0x906a617d450187e2,0x27fb2b80668b24c5,
|
||||
0xb484f9dc9641e9da,0xb1f9f660802dedf6,
|
||||
0xe1a63853bbd26451,0x5e7873f8a0396973,
|
||||
0x8d07e33455637eb2,0xdb0b487b6423e1e8,
|
||||
0xb049dc016abc5e5f,0x91ce1a9a3d2cda62,
|
||||
0xdc5c5301c56b75f7,0x7641a140cc7810fb,
|
||||
0x89b9b3e11b6329ba,0xa9e904c87fcb0a9d,
|
||||
0xac2820d9623bf429,0x546345fa9fbdcd44,
|
||||
0xd732290fbacaf133,0xa97c177947ad4095,
|
||||
0x867f59a9d4bed6c0,0x49ed8eabcccc485d,
|
||||
0xa81f301449ee8c70,0x5c68f256bfff5a74,
|
||||
0xd226fc195c6a2f8c,0x73832eec6fff3111,
|
||||
0x83585d8fd9c25db7,0xc831fd53c5ff7eab,
|
||||
0xa42e74f3d032f525,0xba3e7ca8b77f5e55,
|
||||
0xcd3a1230c43fb26f,0x28ce1bd2e55f35eb,
|
||||
0x80444b5e7aa7cf85,0x7980d163cf5b81b3,
|
||||
0xa0555e361951c366,0xd7e105bcc332621f,
|
||||
0xc86ab5c39fa63440,0x8dd9472bf3fefaa7,
|
||||
0xfa856334878fc150,0xb14f98f6f0feb951,
|
||||
0x9c935e00d4b9d8d2,0x6ed1bf9a569f33d3,
|
||||
0xc3b8358109e84f07,0xa862f80ec4700c8,
|
||||
0xf4a642e14c6262c8,0xcd27bb612758c0fa,
|
||||
0x98e7e9cccfbd7dbd,0x8038d51cb897789c,
|
||||
0xbf21e44003acdd2c,0xe0470a63e6bd56c3,
|
||||
0xeeea5d5004981478,0x1858ccfce06cac74,
|
||||
0x95527a5202df0ccb,0xf37801e0c43ebc8,
|
||||
0xbaa718e68396cffd,0xd30560258f54e6ba,
|
||||
0xe950df20247c83fd,0x47c6b82ef32a2069,
|
||||
0x91d28b7416cdd27e,0x4cdc331d57fa5441,
|
||||
0xb6472e511c81471d,0xe0133fe4adf8e952,
|
||||
0xe3d8f9e563a198e5,0x58180fddd97723a6,
|
||||
0x8e679c2f5e44ff8f,0x570f09eaa7ea7648,};
|
||||
};
|
||||
|
||||
template <class unused>
|
||||
constexpr uint64_t powers_template<unused>::power_of_five_128[number_of_entries];
|
||||
|
||||
using powers = powers_template<>;
|
||||
|
||||
}}}}}} // namespace fast_float
|
||||
|
||||
#endif
|
||||
Vendored
Executable
+562
@@ -0,0 +1,562 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/constexpr_feature_detect.hpp>
|
||||
#include <boost/json/detail/charconv/detail/from_chars_result.hpp>
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <boost/json/detail/charconv/chars_format.hpp>
|
||||
#include <cfloat>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
|
||||
template <typename UC>
|
||||
struct parse_options_t {
|
||||
constexpr explicit parse_options_t(chars_format fmt = chars_format::general,
|
||||
UC dot = UC('.'))
|
||||
: format(fmt), decimal_point(dot) {}
|
||||
|
||||
/** Which number formats are accepted */
|
||||
chars_format format;
|
||||
/** The character used as decimal point */
|
||||
UC decimal_point;
|
||||
};
|
||||
using parse_options = parse_options_t<char>;
|
||||
|
||||
}}}}}}
|
||||
|
||||
#ifdef BOOST_JSON_HAS_BIT_CAST
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
|
||||
|| defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
|
||||
|| defined(__MINGW64__) \
|
||||
|| defined(__s390x__) \
|
||||
|| (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)) )
|
||||
#define BOOST_JSON_FASTFLOAT_64BIT 1
|
||||
#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) \
|
||||
|| defined(__arm__) || defined(_M_ARM) || defined(__ppc__) \
|
||||
|| defined(__MINGW32__) || defined(__EMSCRIPTEN__))
|
||||
#define BOOST_JSON_FASTFLOAT_32BIT 1
|
||||
#else
|
||||
// Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.
|
||||
// We can never tell the register width, but the SIZE_MAX is a good approximation.
|
||||
// UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max portability.
|
||||
#if SIZE_MAX == 0xffff
|
||||
#error Unknown platform (16-bit, unsupported)
|
||||
#elif SIZE_MAX == 0xffffffff
|
||||
#define BOOST_JSON_FASTFLOAT_32BIT 1
|
||||
#elif SIZE_MAX == 0xffffffffffffffff
|
||||
#define BOOST_JSON_FASTFLOAT_64BIT 1
|
||||
#else
|
||||
#error Unknown platform (not 32-bit, not 64-bit?)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__))
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define BOOST_JSON_FASTFLOAT_VISUAL_STUDIO 1
|
||||
#endif
|
||||
|
||||
// rust style `try!()` macro, or `?` operator
|
||||
#define BOOST_JSON_FASTFLOAT_TRY(x) { if (!(x)) return false; }
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
BOOST_FORCEINLINE constexpr bool cpp20_and_in_constexpr() {
|
||||
#ifdef BOOST_JSON_HAS_IS_CONSTANT_EVALUATED
|
||||
return std::is_constant_evaluated();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Compares two ASCII strings in a case insensitive manner.
|
||||
template <typename UC>
|
||||
inline BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE bool
|
||||
fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) {
|
||||
char running_diff{0};
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
running_diff |= (char(input1[i]) ^ char(input2[i]));
|
||||
}
|
||||
return (running_diff == 0) || (running_diff == 32);
|
||||
}
|
||||
|
||||
#ifndef FLT_EVAL_METHOD
|
||||
#error "FLT_EVAL_METHOD should be defined, please include cfloat."
|
||||
#endif
|
||||
|
||||
// a pointer and a length to a contiguous block of memory
|
||||
template <typename T>
|
||||
struct span {
|
||||
const T* ptr;
|
||||
size_t length;
|
||||
constexpr span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {}
|
||||
constexpr span() : ptr(nullptr), length(0) {}
|
||||
|
||||
constexpr size_t len() const noexcept {
|
||||
return length;
|
||||
}
|
||||
|
||||
BOOST_JSON_CXX14_CONSTEXPR const T& operator[](size_t index) const noexcept {
|
||||
BOOST_ASSERT(index < length);
|
||||
return ptr[index];
|
||||
}
|
||||
};
|
||||
|
||||
struct value128 {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
|
||||
constexpr value128() : low(0), high(0) {}
|
||||
};
|
||||
|
||||
/* Helper C++11 constexpr generic implementation of leading_zeroes */
|
||||
BOOST_FORCEINLINE constexpr
|
||||
int leading_zeroes_generic(uint64_t input_num, int last_bit = 0) {
|
||||
return (
|
||||
((input_num & uint64_t(0xffffffff00000000)) && (input_num >>= 32, last_bit |= 32)),
|
||||
((input_num & uint64_t( 0xffff0000)) && (input_num >>= 16, last_bit |= 16)),
|
||||
((input_num & uint64_t( 0xff00)) && (input_num >>= 8, last_bit |= 8)),
|
||||
((input_num & uint64_t( 0xf0)) && (input_num >>= 4, last_bit |= 4)),
|
||||
((input_num & uint64_t( 0xc)) && (input_num >>= 2, last_bit |= 2)),
|
||||
((input_num & uint64_t( 0x2)) && (input_num >>= 1, last_bit |= 1)),
|
||||
63 - last_bit
|
||||
);
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
int leading_zeroes(uint64_t input_num) {
|
||||
assert(input_num > 0);
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
return leading_zeroes_generic(input_num);
|
||||
}
|
||||
#ifdef BOOST_JSON_FASTFLOAT_VISUAL_STUDIO
|
||||
#if defined(_M_X64) || defined(_M_ARM64)
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
_BitScanReverse64(&leading_zero, input_num);
|
||||
return (int)(63 - leading_zero);
|
||||
#else
|
||||
return leading_zeroes_generic(input_num);
|
||||
#endif
|
||||
#else
|
||||
return __builtin_clzll(input_num);
|
||||
#endif
|
||||
}
|
||||
|
||||
// slow emulation routine for 32-bit
|
||||
BOOST_FORCEINLINE constexpr uint64_t emulu(uint32_t x, uint32_t y) {
|
||||
return x * (uint64_t)y;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
uint64_t umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) {
|
||||
uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);
|
||||
uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);
|
||||
uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));
|
||||
uint64_t adbc_carry = !!(adbc < ad);
|
||||
uint64_t lo = bd + (adbc << 32);
|
||||
*hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
|
||||
(adbc_carry << 32) + !!(lo < bd);
|
||||
return lo;
|
||||
}
|
||||
|
||||
#ifdef BOOST_JSON_FASTFLOAT_32BIT
|
||||
|
||||
// slow emulation routine for 32-bit
|
||||
#if !defined(__MINGW64__)
|
||||
BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
|
||||
uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) {
|
||||
return umul128_generic(ab, cd, hi);
|
||||
}
|
||||
#endif // !__MINGW64__
|
||||
|
||||
#endif // BOOST_JSON_FASTFLOAT_32BIT
|
||||
|
||||
|
||||
// compute 64-bit a*b
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
value128 full_multiplication(uint64_t a, uint64_t b) {
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
value128 answer;
|
||||
answer.low = umul128_generic(a, b, &answer.high);
|
||||
return answer;
|
||||
}
|
||||
value128 answer;
|
||||
#if defined(_M_ARM64) && !defined(__MINGW32__)
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emulate
|
||||
// But MinGW on ARM64 doesn't have native support for 64-bit multiplications
|
||||
answer.high = __umulh(a, b);
|
||||
answer.low = a * b;
|
||||
#elif defined(BOOST_JSON_FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__))
|
||||
unsigned long long high;
|
||||
answer.low = _umul128(a, b, &high); // _umul128 not available on ARM64
|
||||
answer.high = static_cast<uint64_t>(high);
|
||||
#elif defined(BOOST_JSON_FASTFLOAT_64BIT)
|
||||
__uint128_t r = ((__uint128_t)a) * b;
|
||||
answer.low = uint64_t(r);
|
||||
answer.high = uint64_t(r >> 64);
|
||||
#else
|
||||
answer.low = umul128_generic(a, b, &answer.high);
|
||||
#endif
|
||||
return answer;
|
||||
}
|
||||
|
||||
struct adjusted_mantissa {
|
||||
uint64_t mantissa{0};
|
||||
int32_t power2{0}; // a negative value indicates an invalid result
|
||||
adjusted_mantissa() = default;
|
||||
constexpr bool operator==(const adjusted_mantissa &o) const {
|
||||
return mantissa == o.mantissa && power2 == o.power2;
|
||||
}
|
||||
constexpr bool operator!=(const adjusted_mantissa &o) const {
|
||||
return mantissa != o.mantissa || power2 != o.power2;
|
||||
}
|
||||
};
|
||||
|
||||
// Bias so we can get the real exponent with an invalid adjusted_mantissa.
|
||||
constexpr static int32_t invalid_am_bias = -0x8000;
|
||||
|
||||
// used for binary_format_lookup_tables<T>::max_mantissa
|
||||
constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5;
|
||||
|
||||
template <typename T, typename U = void>
|
||||
struct binary_format_lookup_tables;
|
||||
|
||||
template <typename T> struct binary_format : binary_format_lookup_tables<T> {
|
||||
using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type;
|
||||
|
||||
static inline constexpr int mantissa_explicit_bits();
|
||||
static inline constexpr int minimum_exponent();
|
||||
static inline constexpr int infinite_power();
|
||||
static inline constexpr int sign_index();
|
||||
static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST
|
||||
static inline constexpr int max_exponent_fast_path();
|
||||
static inline constexpr int max_exponent_round_to_even();
|
||||
static inline constexpr int min_exponent_round_to_even();
|
||||
static inline constexpr uint64_t max_mantissa_fast_path(int64_t power);
|
||||
static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST
|
||||
static inline constexpr int largest_power_of_ten();
|
||||
static inline constexpr int smallest_power_of_ten();
|
||||
static inline constexpr T exact_power_of_ten(int64_t power);
|
||||
static inline constexpr size_t max_digits();
|
||||
static inline constexpr equiv_uint exponent_mask();
|
||||
static inline constexpr equiv_uint mantissa_mask();
|
||||
static inline constexpr equiv_uint hidden_bit_mask();
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
struct binary_format_lookup_tables<double, U> {
|
||||
static constexpr double powers_of_ten[] = {
|
||||
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
|
||||
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
|
||||
|
||||
// Largest integer value v so that (5**index * v) <= 1<<53.
|
||||
// 0x10000000000000 == 1 << 53
|
||||
static constexpr std::uint64_t max_mantissa[] = {
|
||||
UINT64_C(0x10000000000000),
|
||||
UINT64_C(0x10000000000000) / UINT64_C(5),
|
||||
UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5))};
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[];
|
||||
|
||||
template <typename U>
|
||||
constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[];
|
||||
|
||||
template <typename U>
|
||||
struct binary_format_lookup_tables<float, U> {
|
||||
static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f,
|
||||
1e6f, 1e7f, 1e8f, 1e9f, 1e10f};
|
||||
|
||||
// Largest integer value v so that (5**index * v) <= 1<<24.
|
||||
// 0x1000000 == 1<<24
|
||||
static constexpr uint64_t max_mantissa[] = {
|
||||
UINT64_C(0x1000000),
|
||||
UINT64_C(0x1000000) / UINT64_C(5),
|
||||
UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x1000000) / (constant_55555),
|
||||
UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5)),
|
||||
UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)),
|
||||
UINT64_C(0x1000000) / (constant_55555 * constant_55555),
|
||||
UINT64_C(0x1000000) / (constant_55555 * constant_55555 * UINT64_C(5))};
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[];
|
||||
|
||||
template <typename U>
|
||||
constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[];
|
||||
|
||||
template <> inline constexpr int binary_format<double>::min_exponent_fast_path() {
|
||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||
return 0;
|
||||
#else
|
||||
return -22;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<float>::min_exponent_fast_path() {
|
||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||
return 0;
|
||||
#else
|
||||
return -10;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() {
|
||||
return 52;
|
||||
}
|
||||
template <> inline constexpr int binary_format<float>::mantissa_explicit_bits() {
|
||||
return 23;
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<double>::max_exponent_round_to_even() {
|
||||
return 23;
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<float>::max_exponent_round_to_even() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<double>::min_exponent_round_to_even() {
|
||||
return -4;
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<float>::min_exponent_round_to_even() {
|
||||
return -17;
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<double>::minimum_exponent() {
|
||||
return -1023;
|
||||
}
|
||||
template <> inline constexpr int binary_format<float>::minimum_exponent() {
|
||||
return -127;
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<double>::infinite_power() {
|
||||
return 0x7FF;
|
||||
}
|
||||
template <> inline constexpr int binary_format<float>::infinite_power() {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
template <> inline constexpr int binary_format<double>::sign_index() { return 63; }
|
||||
template <> inline constexpr int binary_format<float>::sign_index() { return 31; }
|
||||
|
||||
template <> inline constexpr int binary_format<double>::max_exponent_fast_path() {
|
||||
return 22;
|
||||
}
|
||||
template <> inline constexpr int binary_format<float>::max_exponent_fast_path() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
|
||||
return uint64_t(2) << mantissa_explicit_bits();
|
||||
}
|
||||
template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) {
|
||||
// caller is responsible to ensure that
|
||||
// power >= 0 && power <= 22
|
||||
//
|
||||
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||
return (void)max_mantissa[0], max_mantissa[power];
|
||||
}
|
||||
template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
|
||||
return uint64_t(2) << mantissa_explicit_bits();
|
||||
}
|
||||
template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path(int64_t power) {
|
||||
// caller is responsible to ensure that
|
||||
// power >= 0 && power <= 10
|
||||
//
|
||||
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||
return (void)max_mantissa[0], max_mantissa[power];
|
||||
}
|
||||
|
||||
template <>
|
||||
inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) {
|
||||
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||
return (void)powers_of_ten[0], powers_of_ten[power];
|
||||
}
|
||||
template <>
|
||||
inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
|
||||
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
||||
return (void)powers_of_ten[0], powers_of_ten[power];
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
inline constexpr int binary_format<double>::largest_power_of_ten() {
|
||||
return 308;
|
||||
}
|
||||
template <>
|
||||
inline constexpr int binary_format<float>::largest_power_of_ten() {
|
||||
return 38;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline constexpr int binary_format<double>::smallest_power_of_ten() {
|
||||
return -342;
|
||||
}
|
||||
template <>
|
||||
inline constexpr int binary_format<float>::smallest_power_of_ten() {
|
||||
return -65;
|
||||
}
|
||||
|
||||
template <> inline constexpr size_t binary_format<double>::max_digits() {
|
||||
return 769;
|
||||
}
|
||||
template <> inline constexpr size_t binary_format<float>::max_digits() {
|
||||
return 114;
|
||||
}
|
||||
|
||||
template <> inline constexpr binary_format<float>::equiv_uint
|
||||
binary_format<float>::exponent_mask() {
|
||||
return 0x7F800000;
|
||||
}
|
||||
template <> inline constexpr binary_format<double>::equiv_uint
|
||||
binary_format<double>::exponent_mask() {
|
||||
return 0x7FF0000000000000;
|
||||
}
|
||||
|
||||
template <> inline constexpr binary_format<float>::equiv_uint
|
||||
binary_format<float>::mantissa_mask() {
|
||||
return 0x007FFFFF;
|
||||
}
|
||||
template <> inline constexpr binary_format<double>::equiv_uint
|
||||
binary_format<double>::mantissa_mask() {
|
||||
return 0x000FFFFFFFFFFFFF;
|
||||
}
|
||||
|
||||
template <> inline constexpr binary_format<float>::equiv_uint
|
||||
binary_format<float>::hidden_bit_mask() {
|
||||
return 0x00800000;
|
||||
}
|
||||
template <> inline constexpr binary_format<double>::equiv_uint
|
||||
binary_format<double>::hidden_bit_mask() {
|
||||
return 0x0010000000000000;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
void to_float(bool negative, adjusted_mantissa am, T &value) {
|
||||
using uint = typename binary_format<T>::equiv_uint;
|
||||
uint word = (uint)am.mantissa;
|
||||
word |= uint(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
||||
word |= uint(negative) << binary_format<T>::sign_index();
|
||||
#ifdef BOOST_JSON_HAS_BIT_CAST
|
||||
value = std::bit_cast<T>(word);
|
||||
#else
|
||||
::memcpy(&value, &word, sizeof(T));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename UC>
|
||||
static constexpr uint64_t int_cmp_zeros()
|
||||
{
|
||||
static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size");
|
||||
return (sizeof(UC) == 1) ? 0x3030303030303030 : (sizeof(UC) == 2) ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | uint64_t(UC('0')) << 16 | UC('0')) : (uint64_t(UC('0')) << 32 | UC('0'));
|
||||
}
|
||||
template<typename UC>
|
||||
static constexpr int int_cmp_len()
|
||||
{
|
||||
return sizeof(uint64_t) / sizeof(UC);
|
||||
}
|
||||
template<typename UC>
|
||||
static constexpr UC const * str_const_nan()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
template<>
|
||||
constexpr char const * str_const_nan<char>()
|
||||
{
|
||||
return "nan";
|
||||
}
|
||||
template<>
|
||||
constexpr wchar_t const * str_const_nan<wchar_t>()
|
||||
{
|
||||
return L"nan";
|
||||
}
|
||||
template<>
|
||||
constexpr char16_t const * str_const_nan<char16_t>()
|
||||
{
|
||||
return u"nan";
|
||||
}
|
||||
template<>
|
||||
constexpr char32_t const * str_const_nan<char32_t>()
|
||||
{
|
||||
return U"nan";
|
||||
}
|
||||
template<typename UC>
|
||||
static constexpr UC const * str_const_inf()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
template<>
|
||||
constexpr char const * str_const_inf<char>()
|
||||
{
|
||||
return "infinity";
|
||||
}
|
||||
template<>
|
||||
constexpr wchar_t const * str_const_inf<wchar_t>()
|
||||
{
|
||||
return L"infinity";
|
||||
}
|
||||
template<>
|
||||
constexpr char16_t const * str_const_inf<char16_t>()
|
||||
{
|
||||
return u"infinity";
|
||||
}
|
||||
template<>
|
||||
constexpr char32_t const * str_const_inf<char32_t>()
|
||||
{
|
||||
return U"infinity";
|
||||
}
|
||||
|
||||
}}}}}} // namespaces
|
||||
|
||||
#endif
|
||||
Vendored
Executable
+237
@@ -0,0 +1,237 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
//
|
||||
// Derivative of: https://github.com/fastfloat/fast_float
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_PARSE_NUMBER_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_PARSE_NUMBER_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/ascii_number.hpp>
|
||||
#include <boost/json/detail/charconv/detail/fast_float/decimal_to_binary.hpp>
|
||||
#include <boost/json/detail/charconv/detail/fast_float/digit_comparison.hpp>
|
||||
#include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
|
||||
|
||||
|
||||
namespace detail {
|
||||
/**
|
||||
* Special case +inf, -inf, nan, infinity, -infinity.
|
||||
* The case comparisons could be made much faster given that we know that the
|
||||
* strings a null-free and fixed.
|
||||
**/
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
template <typename T, typename UC>
|
||||
from_chars_result_t<UC> BOOST_JSON_CXX14_CONSTEXPR
|
||||
parse_infnan(UC const * first, UC const * last, T &value) noexcept {
|
||||
from_chars_result_t<UC> answer{};
|
||||
answer.ptr = first;
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
bool minusSign = false;
|
||||
if (*first == UC('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
|
||||
minusSign = true;
|
||||
++first;
|
||||
}
|
||||
if (last - first >= 3) {
|
||||
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
|
||||
answer.ptr = (first += 3);
|
||||
value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
|
||||
// Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
|
||||
if(first != last && *first == UC('(')) {
|
||||
for(UC const * ptr = first + 1; ptr != last; ++ptr) {
|
||||
if (*ptr == UC(')')) {
|
||||
answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
|
||||
break;
|
||||
}
|
||||
else if(!((UC('a') <= *ptr && *ptr <= UC('z')) || (UC('A') <= *ptr && *ptr <= UC('Z')) || (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
|
||||
break; // forbidden char, not nan(n-char-seq-opt)
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
|
||||
if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
|
||||
answer.ptr = first + 8;
|
||||
} else {
|
||||
answer.ptr = first + 3;
|
||||
}
|
||||
value = minusSign ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity();
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
return answer;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns true if the floating-pointing rounding mode is to 'nearest'.
|
||||
* It is the default on most system. This function is meant to be inexpensive.
|
||||
* Credit : @mwalcott3
|
||||
*/
|
||||
BOOST_FORCEINLINE bool rounds_to_nearest() noexcept {
|
||||
// https://lemire.me/blog/2020/06/26/gcc-not-nearest/
|
||||
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
|
||||
return false;
|
||||
#endif
|
||||
// See
|
||||
// A fast function to check your floating-point rounding mode
|
||||
// https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/
|
||||
//
|
||||
// This function is meant to be equivalent to :
|
||||
// prior: #include <cfenv>
|
||||
// return fegetround() == FE_TONEAREST;
|
||||
// However, it is expected to be much faster than the fegetround()
|
||||
// function call.
|
||||
//
|
||||
// The volatile keywoard prevents the compiler from computing the function
|
||||
// at compile-time.
|
||||
// There might be other ways to prevent compile-time optimizations (e.g., asm).
|
||||
// The value does not need to be std::numeric_limits<float>::min(), any small
|
||||
// value so that 1 + x should round to 1 would do (after accounting for excess
|
||||
// precision, as in 387 instructions).
|
||||
static volatile float fmin = (std::numeric_limits<float>::min)();
|
||||
float fmini = fmin; // we copy it so that it gets loaded at most once.
|
||||
//
|
||||
// Explanation:
|
||||
// Only when fegetround() == FE_TONEAREST do we have that
|
||||
// fmin + 1.0f == 1.0f - fmin.
|
||||
//
|
||||
// FE_UPWARD:
|
||||
// fmin + 1.0f > 1
|
||||
// 1.0f - fmin == 1
|
||||
//
|
||||
// FE_DOWNWARD or FE_TOWARDZERO:
|
||||
// fmin + 1.0f == 1
|
||||
// 1.0f - fmin < 1
|
||||
//
|
||||
// Note: This may fail to be accurate if fast-math has been
|
||||
// enabled, as rounding conventions may not apply.
|
||||
#ifdef BOOST_JSON_FASTFLOAT_VISUAL_STUDIO
|
||||
# pragma warning(push)
|
||||
// todo: is there a VS warning?
|
||||
// see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
return (fmini + 1.0f == 1.0f - fmini);
|
||||
#ifdef BOOST_JSON_FASTFLOAT_VISUAL_STUDIO
|
||||
# pragma warning(pop)
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename UC>
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||
return from_chars_advanced(first, last, value, parse_options_t<UC>{fmt});
|
||||
}
|
||||
|
||||
template<typename T, typename UC>
|
||||
BOOST_JSON_FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
T &value, parse_options_t<UC> options) noexcept {
|
||||
|
||||
static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");
|
||||
static_assert (std::is_same<UC, char>::value ||
|
||||
std::is_same<UC, wchar_t>::value ||
|
||||
std::is_same<UC, char16_t>::value ||
|
||||
std::is_same<UC, char32_t>::value , "only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
if (first == last) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options);
|
||||
if (!pns.valid) {
|
||||
return detail::parse_infnan(first, last, value);
|
||||
}
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
answer.ptr = pns.lastmatch;
|
||||
// The implementation of the Clinger's fast path is convoluted because
|
||||
// we want round-to-nearest in all cases, irrespective of the rounding mode
|
||||
// selected on the thread.
|
||||
// We proceed optimistically, assuming that detail::rounds_to_nearest() returns
|
||||
// true.
|
||||
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && !pns.too_many_digits) {
|
||||
// Unfortunately, the conventional Clinger's fast path is only possible
|
||||
// when the system rounds to the nearest float.
|
||||
//
|
||||
// We expect the next branch to almost always be selected.
|
||||
// We could check it first (before the previous branch), but
|
||||
// there might be performance advantages at having the check
|
||||
// be last.
|
||||
if(!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) {
|
||||
// We have that fegetround() == FE_TONEAREST.
|
||||
// Next is Clinger's fast path.
|
||||
if (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
||||
value = T(pns.mantissa);
|
||||
if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
|
||||
else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
|
||||
if (pns.negative) { value = -value; }
|
||||
return answer;
|
||||
}
|
||||
} else {
|
||||
// We do not have that fegetround() == FE_TONEAREST.
|
||||
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's proposal
|
||||
if (pns.exponent >= 0 && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
|
||||
#if defined(__clang__)
|
||||
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
||||
if(pns.mantissa == 0) {
|
||||
value = pns.negative ? -0. : 0.;
|
||||
return answer;
|
||||
}
|
||||
#endif
|
||||
value = T(pns.mantissa) * binary_format<T>::exact_power_of_ten(pns.exponent);
|
||||
if (pns.negative) { value = -value; }
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
}
|
||||
adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||
if(pns.too_many_digits && am.power2 >= 0) {
|
||||
if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
|
||||
am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa);
|
||||
}
|
||||
}
|
||||
// If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa) and we have an invalid power (am.power2 < 0),
|
||||
// then we need to go the long way around again. This is very uncommon.
|
||||
if(am.power2 < 0) { am = digit_comp<T>(pns, am); }
|
||||
to_float(pns.negative, am, value);
|
||||
// Test for over/underflow.
|
||||
if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || am.power2 == binary_format<T>::infinite_power()) {
|
||||
answer.ec = std::errc::result_out_of_range;
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
}}}}}} // namespace fast_float
|
||||
|
||||
#endif
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
// Copyright 2022 Peter Dimov
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_FLOAT_IMPL_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_FLOAT_IMPL_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <boost/json/detail/charconv/detail/from_chars_result.hpp>
|
||||
#include <boost/json/detail/charconv/detail/parser.hpp>
|
||||
#include <boost/json/detail/charconv/detail/compute_float64.hpp>
|
||||
#include <boost/json/detail/charconv/chars_format.hpp>
|
||||
#include <system_error>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4244) // Implict converion when BOOST_IF_CONSTEXPR expands to if
|
||||
#elif defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
from_chars_result from_chars_strtod_impl(const char* first, const char* last, T& value, char* buffer) noexcept
|
||||
{
|
||||
// For strto(f/d)
|
||||
// Floating point value corresponding to the contents of str on success.
|
||||
// If the converted value falls out of range of corresponding return type, range error occurs and HUGE_VAL, HUGE_VALF or HUGE_VALL is returned.
|
||||
// If no conversion can be performed, 0 is returned and *str_end is set to str.
|
||||
|
||||
std::memcpy(buffer, first, static_cast<std::size_t>(last - first));
|
||||
buffer[last - first] = '\0';
|
||||
|
||||
char* str_end;
|
||||
T return_value {};
|
||||
BOOST_IF_CONSTEXPR (std::is_same<T, float>::value)
|
||||
{
|
||||
return_value = std::strtof(buffer, &str_end);
|
||||
if (return_value == HUGE_VALF)
|
||||
{
|
||||
return {last, std::errc::result_out_of_range};
|
||||
}
|
||||
}
|
||||
else BOOST_IF_CONSTEXPR (std::is_same<T, double>::value)
|
||||
{
|
||||
return_value = std::strtod(buffer, &str_end);
|
||||
if (return_value == HUGE_VAL)
|
||||
{
|
||||
return {last, std::errc::result_out_of_range};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return_value = std::strtold(buffer, &str_end);
|
||||
if (return_value == HUGE_VALL)
|
||||
{
|
||||
return {last, std::errc::result_out_of_range};
|
||||
}
|
||||
}
|
||||
|
||||
// Since this is a fallback routine we are safe to check for 0
|
||||
if (return_value == 0 && str_end == last)
|
||||
{
|
||||
return {first, std::errc::result_out_of_range};
|
||||
}
|
||||
|
||||
value = return_value;
|
||||
return {first + (str_end - buffer), std::errc()};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline from_chars_result from_chars_strtod(const char* first, const char* last, T& value) noexcept
|
||||
{
|
||||
if (last - first < 1024)
|
||||
{
|
||||
char buffer[1024];
|
||||
return from_chars_strtod_impl(first, last, value, buffer);
|
||||
}
|
||||
|
||||
// If the string to be parsed does not fit into the 1024 byte static buffer than we have to allocate a buffer.
|
||||
// malloc is used here because it does not throw on allocation failure.
|
||||
|
||||
char* buffer = static_cast<char*>(std::malloc(last - first + 1));
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
return {first, std::errc::not_enough_memory};
|
||||
}
|
||||
|
||||
auto r = from_chars_strtod_impl(first, last, value, buffer);
|
||||
std::free(buffer);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
from_chars_result from_chars_float_impl(const char* first, const char* last, T& value, chars_format fmt) noexcept
|
||||
{
|
||||
bool sign {};
|
||||
std::uint64_t significand {};
|
||||
std::int64_t exponent {};
|
||||
|
||||
auto r = charconv::detail::parser(first, last, sign, significand, exponent, fmt);
|
||||
if (r.ec != std::errc())
|
||||
{
|
||||
return r;
|
||||
}
|
||||
else if (significand == 0)
|
||||
{
|
||||
value = sign ? static_cast<T>(-0.0L) : static_cast<T>(0.0L);
|
||||
return r;
|
||||
}
|
||||
else if (exponent == -1)
|
||||
{
|
||||
// A full length significand e.g. -1985444280612224 with a power of -1 sometimes
|
||||
// fails in compute_float64 but is trivial to calculate
|
||||
// Found investigating GitHub issue #47
|
||||
value = (sign ? -static_cast<T>(significand) : static_cast<T>(significand)) / 10;
|
||||
}
|
||||
|
||||
bool success {};
|
||||
T return_val {};
|
||||
return_val = compute_float64(exponent, significand, sign, success);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
if (significand == 1 && exponent == 0)
|
||||
{
|
||||
value = 1;
|
||||
r.ptr = last;
|
||||
r.ec = std::errc();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (return_val == HUGE_VAL || return_val == -HUGE_VAL)
|
||||
{
|
||||
value = return_val;
|
||||
r.ec = std::errc::result_out_of_range;
|
||||
}
|
||||
else if (exponent < -342)
|
||||
{
|
||||
value = sign ? -0.0 : 0.0;
|
||||
r.ec = std::errc::result_out_of_range;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = from_chars_strtod(first, r.ptr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = return_val;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#elif defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
}}}}} // Namespace boost::charconv::detail
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_FLOAT_IMPL_HPP
|
||||
Vendored
Executable
+252
@@ -0,0 +1,252 @@
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <boost/json/detail/charconv/detail/from_chars_result.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <cstdlib>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
|
||||
|
||||
static constexpr unsigned char uchar_values[] =
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
|
||||
|
||||
static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char");
|
||||
|
||||
// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255
|
||||
constexpr unsigned char digit_from_char(char val) noexcept
|
||||
{
|
||||
return uchar_values[static_cast<unsigned char>(val)];
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
# pragma warning(disable: 4189) // 'is_negative': local variable is initialized but not referenced
|
||||
|
||||
#elif defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wconstant-conversion"
|
||||
|
||||
#elif defined(__GNUC__) && (__GNUC__ < 7)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Woverflow"
|
||||
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 7)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
|
||||
#endif
|
||||
|
||||
template <typename Integer, typename Unsigned_Integer>
|
||||
BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept
|
||||
{
|
||||
Unsigned_Integer result = 0;
|
||||
Unsigned_Integer overflow_value = 0;
|
||||
Unsigned_Integer max_digit = 0;
|
||||
|
||||
// Check pre-conditions
|
||||
if (!((first <= last) && (base >= 2 && base <= 36)))
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
Unsigned_Integer unsigned_base = static_cast<Unsigned_Integer>(base);
|
||||
|
||||
// Strip sign if the type is signed
|
||||
// Negative sign will be appended at the end of parsing
|
||||
BOOST_ATTRIBUTE_UNUSED bool is_negative = false;
|
||||
auto next = first;
|
||||
|
||||
#ifdef BOOST_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value || std::is_signed<Integer>::value)
|
||||
#else
|
||||
BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value)
|
||||
#endif
|
||||
{
|
||||
if (next != last)
|
||||
{
|
||||
if (*next == '-')
|
||||
{
|
||||
is_negative = true;
|
||||
++next;
|
||||
}
|
||||
else if (*next == '+')
|
||||
{
|
||||
return {next, std::errc::invalid_argument};
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value)
|
||||
{
|
||||
overflow_value = BOOST_JSON_INT128_MAX;
|
||||
max_digit = BOOST_JSON_INT128_MAX;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
overflow_value = (std::numeric_limits<Integer>::max)();
|
||||
max_digit = (std::numeric_limits<Integer>::max)();
|
||||
}
|
||||
|
||||
if (is_negative)
|
||||
{
|
||||
++overflow_value;
|
||||
++max_digit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next != last && (*next == '-' || *next == '+'))
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::uint128_type>::value)
|
||||
{
|
||||
overflow_value = BOOST_JSON_UINT128_MAX;
|
||||
max_digit = BOOST_JSON_UINT128_MAX;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
overflow_value = (std::numeric_limits<Unsigned_Integer>::max)();
|
||||
max_digit = (std::numeric_limits<Unsigned_Integer>::max)();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value)
|
||||
{
|
||||
overflow_value /= unsigned_base;
|
||||
max_digit %= unsigned_base;
|
||||
overflow_value *= 2; // Overflow value would cause INT128_MIN in non-base10 to fail
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
overflow_value /= unsigned_base;
|
||||
max_digit %= unsigned_base;
|
||||
}
|
||||
|
||||
// If the only character was a sign abort now
|
||||
if (next == last)
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
bool overflowed = false;
|
||||
|
||||
std::ptrdiff_t nc = last - next;
|
||||
constexpr std::ptrdiff_t nd = std::numeric_limits<Integer>::digits10;
|
||||
|
||||
{
|
||||
std::ptrdiff_t i = 0;
|
||||
|
||||
for( ; i < nd && i < nc; ++i )
|
||||
{
|
||||
// overflow is not possible in the first nd characters
|
||||
|
||||
const unsigned char current_digit = digit_from_char(*next);
|
||||
|
||||
if (current_digit >= unsigned_base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit);
|
||||
++next;
|
||||
}
|
||||
|
||||
for( ; i < nc; ++i )
|
||||
{
|
||||
const unsigned char current_digit = digit_from_char(*next);
|
||||
|
||||
if (current_digit >= unsigned_base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (result < overflow_value || (result == overflow_value && current_digit <= max_digit))
|
||||
{
|
||||
result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Required to keep updating the value of next, but the result is garbage
|
||||
overflowed = true;
|
||||
}
|
||||
|
||||
++next;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the parsed value, adding the sign back if applicable
|
||||
// If we have overflowed then we do not return the result
|
||||
if (overflowed)
|
||||
{
|
||||
return {next, std::errc::result_out_of_range};
|
||||
}
|
||||
|
||||
value = static_cast<Integer>(result);
|
||||
#ifdef BOOST_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value || std::is_signed<Integer>::value)
|
||||
#else
|
||||
BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value)
|
||||
#endif
|
||||
{
|
||||
if (is_negative)
|
||||
{
|
||||
value = -(static_cast<Unsigned_Integer>(value));
|
||||
}
|
||||
}
|
||||
|
||||
return {next, std::errc()};
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#elif defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__) && (__GNUC__ < 7 || __GNUC__ >= 9)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// Only from_chars for integer types is constexpr (as of C++23)
|
||||
template <typename Integer>
|
||||
BOOST_JSON_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept
|
||||
{
|
||||
using Unsigned_Integer = typename std::make_unsigned<Integer>::type;
|
||||
return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base);
|
||||
}
|
||||
|
||||
}}}}} // Namespaces
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv {
|
||||
|
||||
// 22.13.3, Primitive numerical input conversion
|
||||
|
||||
template <typename UC>
|
||||
struct from_chars_result_t
|
||||
{
|
||||
const UC* ptr;
|
||||
|
||||
// Values:
|
||||
// 0 = no error
|
||||
// EINVAL = invalid_argument
|
||||
// ERANGE = result_out_of_range
|
||||
std::errc ec;
|
||||
|
||||
friend constexpr bool operator==(const from_chars_result_t<UC>& lhs, const from_chars_result_t<UC>& rhs) noexcept
|
||||
{
|
||||
return lhs.ptr == rhs.ptr && lhs.ec == rhs.ec;
|
||||
}
|
||||
|
||||
friend constexpr bool operator!=(const from_chars_result_t<UC>& lhs, const from_chars_result_t<UC>& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
using from_chars_result = from_chars_result_t<char>;
|
||||
|
||||
}}}} // Namespaces
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP
|
||||
|
||||
// https://stackoverflow.com/questions/1489830/efficient-way-to-determine-number-of-digits-in-an-integer?page=1&tab=scoredesc#tab-top
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html
|
||||
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <limits>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
|
||||
|
||||
// Generic solution
|
||||
template <typename T>
|
||||
BOOST_JSON_CXX14_CONSTEXPR int num_digits(T x) noexcept
|
||||
{
|
||||
int digits = 0;
|
||||
|
||||
while (x)
|
||||
{
|
||||
x /= 10;
|
||||
++digits;
|
||||
}
|
||||
|
||||
return digits;
|
||||
}
|
||||
|
||||
template <>
|
||||
BOOST_JSON_CXX14_CONSTEXPR int num_digits(std::uint32_t x) noexcept
|
||||
{
|
||||
if (x >= UINT32_C(10000))
|
||||
{
|
||||
if (x >= UINT32_C(10000000))
|
||||
{
|
||||
if (x >= UINT32_C(100000000))
|
||||
{
|
||||
if (x >= UINT32_C(1000000000))
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
|
||||
else if (x >= UINT32_C(100000))
|
||||
{
|
||||
if (x >= UINT32_C(1000000))
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
else if (x >= UINT32_C(100))
|
||||
{
|
||||
if (x >= UINT32_C(1000))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
else if (x >= UINT32_C(10))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
BOOST_JSON_CXX14_CONSTEXPR int num_digits(std::uint64_t x) noexcept
|
||||
{
|
||||
if (x >= UINT64_C(10000000000))
|
||||
{
|
||||
if (x >= UINT64_C(100000000000000))
|
||||
{
|
||||
if (x >= UINT64_C(10000000000000000))
|
||||
{
|
||||
if (x >= UINT64_C(100000000000000000))
|
||||
{
|
||||
if (x >= UINT64_C(1000000000000000000))
|
||||
{
|
||||
if (x >= UINT64_C(10000000000000000000))
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
return 19;
|
||||
}
|
||||
return 18;
|
||||
}
|
||||
return 17;
|
||||
}
|
||||
else if (x >= UINT64_C(1000000000000000))
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
return 15;
|
||||
}
|
||||
if (x >= UINT64_C(1000000000000))
|
||||
{
|
||||
if (x >= UINT64_C(10000000000000))
|
||||
{
|
||||
return 14;
|
||||
}
|
||||
return 13;
|
||||
}
|
||||
if (x >= UINT64_C(100000000000))
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
return 11;
|
||||
}
|
||||
else if (x >= UINT64_C(100000))
|
||||
{
|
||||
if (x >= UINT64_C(10000000))
|
||||
{
|
||||
if (x >= UINT64_C(100000000))
|
||||
{
|
||||
if (x >= UINT64_C(1000000000))
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
if (x >= UINT64_C(1000000))
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
if (x >= UINT64_C(100))
|
||||
{
|
||||
if (x >= UINT64_C(1000))
|
||||
{
|
||||
if (x >= UINT64_C(10000))
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (x >= UINT64_C(10))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_INT128
|
||||
static constexpr std::array<std::uint64_t, 20> powers_of_10 =
|
||||
{{
|
||||
UINT64_C(1), UINT64_C(10), UINT64_C(100), UINT64_C(1000), UINT64_C(10000), UINT64_C(100000), UINT64_C(1000000),
|
||||
UINT64_C(10000000), UINT64_C(100000000), UINT64_C(1000000000), UINT64_C(10000000000), UINT64_C(100000000000),
|
||||
UINT64_C(1000000000000), UINT64_C(10000000000000), UINT64_C(100000000000000), UINT64_C(1000000000000000),
|
||||
UINT64_C(10000000000000000), UINT64_C(100000000000000000), UINT64_C(1000000000000000000), UINT64_C(10000000000000000000)
|
||||
}};
|
||||
|
||||
// Assume that if someone is using 128 bit ints they are favoring the top end of the range
|
||||
// Max value is 340,282,366,920,938,463,463,374,607,431,768,211,455 (39 digits)
|
||||
BOOST_JSON_CXX14_CONSTEXPR int num_digits(boost::uint128_type x) noexcept
|
||||
{
|
||||
// There is not literal for boost::uint128_type so we need to calculate them using the max value of the
|
||||
// std::uint64_t powers of 10
|
||||
constexpr boost::uint128_type digits_39 = static_cast<boost::uint128_type>(UINT64_C(10000000000000000000)) *
|
||||
static_cast<boost::uint128_type>(UINT64_C(10000000000000000000));
|
||||
|
||||
constexpr boost::uint128_type digits_38 = digits_39 / 10;
|
||||
constexpr boost::uint128_type digits_37 = digits_38 / 10;
|
||||
constexpr boost::uint128_type digits_36 = digits_37 / 10;
|
||||
constexpr boost::uint128_type digits_35 = digits_36 / 10;
|
||||
constexpr boost::uint128_type digits_34 = digits_35 / 10;
|
||||
constexpr boost::uint128_type digits_33 = digits_34 / 10;
|
||||
constexpr boost::uint128_type digits_32 = digits_33 / 10;
|
||||
constexpr boost::uint128_type digits_31 = digits_32 / 10;
|
||||
constexpr boost::uint128_type digits_30 = digits_31 / 10;
|
||||
constexpr boost::uint128_type digits_29 = digits_30 / 10;
|
||||
constexpr boost::uint128_type digits_28 = digits_29 / 10;
|
||||
constexpr boost::uint128_type digits_27 = digits_28 / 10;
|
||||
constexpr boost::uint128_type digits_26 = digits_27 / 10;
|
||||
constexpr boost::uint128_type digits_25 = digits_26 / 10;
|
||||
constexpr boost::uint128_type digits_24 = digits_25 / 10;
|
||||
constexpr boost::uint128_type digits_23 = digits_24 / 10;
|
||||
constexpr boost::uint128_type digits_22 = digits_23 / 10;
|
||||
constexpr boost::uint128_type digits_21 = digits_22 / 10;
|
||||
|
||||
return (x >= digits_39) ? 39 :
|
||||
(x >= digits_38) ? 38 :
|
||||
(x >= digits_37) ? 37 :
|
||||
(x >= digits_36) ? 36 :
|
||||
(x >= digits_35) ? 35 :
|
||||
(x >= digits_34) ? 34 :
|
||||
(x >= digits_33) ? 33 :
|
||||
(x >= digits_32) ? 32 :
|
||||
(x >= digits_31) ? 31 :
|
||||
(x >= digits_30) ? 30 :
|
||||
(x >= digits_29) ? 29 :
|
||||
(x >= digits_28) ? 28 :
|
||||
(x >= digits_27) ? 27 :
|
||||
(x >= digits_26) ? 26 :
|
||||
(x >= digits_25) ? 25 :
|
||||
(x >= digits_24) ? 24 :
|
||||
(x >= digits_23) ? 23 :
|
||||
(x >= digits_22) ? 22 :
|
||||
(x >= digits_21) ? 21 :
|
||||
(x >= powers_of_10[19]) ? 20 :
|
||||
(x >= powers_of_10[18]) ? 19 :
|
||||
(x >= powers_of_10[17]) ? 18 :
|
||||
(x >= powers_of_10[16]) ? 17 :
|
||||
(x >= powers_of_10[15]) ? 16 :
|
||||
(x >= powers_of_10[14]) ? 15 :
|
||||
(x >= powers_of_10[13]) ? 14 :
|
||||
(x >= powers_of_10[12]) ? 13 :
|
||||
(x >= powers_of_10[11]) ? 12 :
|
||||
(x >= powers_of_10[10]) ? 11 :
|
||||
(x >= powers_of_10[9]) ? 10 :
|
||||
(x >= powers_of_10[8]) ? 9 :
|
||||
(x >= powers_of_10[7]) ? 8 :
|
||||
(x >= powers_of_10[6]) ? 7 :
|
||||
(x >= powers_of_10[5]) ? 6 :
|
||||
(x >= powers_of_10[4]) ? 5 :
|
||||
(x >= powers_of_10[3]) ? 4 :
|
||||
(x >= powers_of_10[2]) ? 3 :
|
||||
(x >= powers_of_10[1]) ? 2 :
|
||||
(x >= powers_of_10[0]) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}}}}} // Namespace boost::json::detail::charconv::detail
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP
|
||||
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <boost/json/detail/charconv/detail/from_chars_result.hpp>
|
||||
#include <boost/json/detail/charconv/detail/from_chars_integer_impl.hpp>
|
||||
#include <boost/json/detail/charconv/detail/integer_search_trees.hpp>
|
||||
#include <boost/json/detail/charconv/limits.hpp>
|
||||
#include <boost/json/detail/charconv/chars_format.hpp>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
|
||||
|
||||
inline bool is_integer_char(char c) noexcept
|
||||
{
|
||||
return (c >= '0') && (c <= '9');
|
||||
}
|
||||
|
||||
inline bool is_hex_char(char c) noexcept
|
||||
{
|
||||
return is_integer_char(c) || (((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')));
|
||||
}
|
||||
|
||||
inline bool is_delimiter(char c, chars_format fmt) noexcept
|
||||
{
|
||||
if (fmt != chars_format::hex)
|
||||
{
|
||||
return !is_integer_char(c) && c != 'e' && c != 'E';
|
||||
}
|
||||
|
||||
return !is_hex_char(c) && c != 'p' && c != 'P';
|
||||
}
|
||||
|
||||
template <typename Unsigned_Integer, typename Integer>
|
||||
inline from_chars_result parser(const char* first, const char* last, bool& sign, Unsigned_Integer& significand, Integer& exponent, chars_format fmt = chars_format::general) noexcept
|
||||
{
|
||||
if (first > last)
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
auto next = first;
|
||||
bool all_zeros = true;
|
||||
|
||||
// First extract the sign
|
||||
if (*next == '-')
|
||||
{
|
||||
sign = true;
|
||||
++next;
|
||||
}
|
||||
else if (*next == '+')
|
||||
{
|
||||
return {next, std::errc::invalid_argument};
|
||||
}
|
||||
else
|
||||
{
|
||||
sign = false;
|
||||
}
|
||||
|
||||
// Ignore leading zeros (e.g. 00005 or -002.3e+5)
|
||||
while (*next == '0' && next != last)
|
||||
{
|
||||
++next;
|
||||
}
|
||||
|
||||
// If the number is 0 we can abort now
|
||||
char exp_char;
|
||||
char capital_exp_char;
|
||||
if (fmt != chars_format::hex)
|
||||
{
|
||||
exp_char = 'e';
|
||||
capital_exp_char = 'E';
|
||||
}
|
||||
else
|
||||
{
|
||||
exp_char = 'p';
|
||||
capital_exp_char = 'P';
|
||||
}
|
||||
|
||||
if (next == last || *next == exp_char || *next == -capital_exp_char)
|
||||
{
|
||||
significand = 0;
|
||||
exponent = 0;
|
||||
return {next, std::errc()};
|
||||
}
|
||||
|
||||
// Next we get the significand
|
||||
constexpr std::size_t significand_buffer_size = limits<Unsigned_Integer>::max_chars10 - 1; // Base 10 or 16
|
||||
char significand_buffer[significand_buffer_size] {};
|
||||
std::size_t i = 0;
|
||||
std::size_t dot_position = 0;
|
||||
Integer extra_zeros = 0;
|
||||
Integer leading_zero_powers = 0;
|
||||
const auto char_validation_func = (fmt != charconv::chars_format::hex) ? is_integer_char : is_hex_char;
|
||||
const int base = (fmt != charconv::chars_format::hex) ? 10 : 16;
|
||||
|
||||
while (char_validation_func(*next) && next != last && i < significand_buffer_size)
|
||||
{
|
||||
all_zeros = false;
|
||||
significand_buffer[i] = *next;
|
||||
++next;
|
||||
++i;
|
||||
}
|
||||
|
||||
bool fractional = false;
|
||||
if (next == last)
|
||||
{
|
||||
// if fmt is chars_format::scientific the e is required
|
||||
if (fmt == chars_format::scientific)
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
exponent = 0;
|
||||
std::size_t offset = i;
|
||||
|
||||
from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base);
|
||||
switch (r.ec)
|
||||
{
|
||||
case std::errc::invalid_argument:
|
||||
return {first, std::errc::invalid_argument};
|
||||
case std::errc::result_out_of_range:
|
||||
return {next, std::errc::result_out_of_range};
|
||||
default:
|
||||
return {next, std::errc()};
|
||||
}
|
||||
}
|
||||
else if (*next == '.')
|
||||
{
|
||||
++next;
|
||||
fractional = true;
|
||||
dot_position = i;
|
||||
|
||||
// Process the fractional part if we have it
|
||||
//
|
||||
// if fmt is chars_format::scientific the e is required
|
||||
// if fmt is chars_format::fixed and not scientific the e is disallowed
|
||||
// if fmt is chars_format::general (which is scientific and fixed) the e is optional
|
||||
|
||||
// If we have the value 0.00001 we can continue to chop zeros and adjust the exponent
|
||||
// so that we get the useful parts of the fraction
|
||||
if (all_zeros)
|
||||
{
|
||||
while (*next == '0' && next != last)
|
||||
{
|
||||
++next;
|
||||
--leading_zero_powers;
|
||||
}
|
||||
|
||||
if (next == last)
|
||||
{
|
||||
return {last, std::errc()};
|
||||
}
|
||||
}
|
||||
|
||||
while (char_validation_func(*next) && next != last && i < significand_buffer_size)
|
||||
{
|
||||
significand_buffer[i] = *next;
|
||||
++next;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == significand_buffer_size)
|
||||
{
|
||||
// We can not process any more significant figures into the significand so skip to the end
|
||||
// or the exponent part and capture the additional orders of magnitude for the exponent
|
||||
bool found_dot = false;
|
||||
while ((char_validation_func(*next) || *next == '.') && next != last)
|
||||
{
|
||||
++next;
|
||||
if (!fractional && !found_dot)
|
||||
{
|
||||
++extra_zeros;
|
||||
}
|
||||
if (*next == '.')
|
||||
{
|
||||
found_dot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next == last || is_delimiter(*next, fmt))
|
||||
{
|
||||
if (fmt == chars_format::scientific)
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
if (dot_position != 0 || fractional)
|
||||
{
|
||||
exponent = static_cast<Integer>(dot_position) - i + extra_zeros + leading_zero_powers;
|
||||
}
|
||||
else
|
||||
{
|
||||
exponent = extra_zeros + leading_zero_powers;
|
||||
}
|
||||
std::size_t offset = i;
|
||||
|
||||
from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base);
|
||||
switch (r.ec)
|
||||
{
|
||||
case std::errc::invalid_argument:
|
||||
return {first, std::errc::invalid_argument};
|
||||
case std::errc::result_out_of_range:
|
||||
return {next, std::errc::result_out_of_range};
|
||||
default:
|
||||
return {next, std::errc()};
|
||||
}
|
||||
}
|
||||
else if (*next == exp_char || *next == capital_exp_char)
|
||||
{
|
||||
// Would be a number without a significand e.g. e+03
|
||||
if (next == first)
|
||||
{
|
||||
return {next, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
++next;
|
||||
if (fmt == chars_format::fixed)
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
exponent = i - 1;
|
||||
std::size_t offset = i;
|
||||
bool round = false;
|
||||
// If more digits are present than representable in the significand of the target type
|
||||
// we set the maximum
|
||||
if (offset > significand_buffer_size)
|
||||
{
|
||||
offset = significand_buffer_size - 1;
|
||||
i = significand_buffer_size;
|
||||
if (significand_buffer[offset] == '5' ||
|
||||
significand_buffer[offset] == '6' ||
|
||||
significand_buffer[offset] == '7' ||
|
||||
significand_buffer[offset] == '8' ||
|
||||
significand_buffer[offset] == '9')
|
||||
{
|
||||
round = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the significand is 0 from chars will return std::errc::invalid_argument because there is nothing in the buffer,
|
||||
// but it is a valid value. We need to continue parsing to get the correct value of ptr even
|
||||
// though we know we could bail now.
|
||||
//
|
||||
// See GitHub issue #29: https://github.com/cppalliance/charconv/issues/29
|
||||
if (offset != 0)
|
||||
{
|
||||
from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base);
|
||||
switch (r.ec)
|
||||
{
|
||||
case std::errc::invalid_argument:
|
||||
return {first, std::errc::invalid_argument};
|
||||
case std::errc::result_out_of_range:
|
||||
return {next, std::errc::result_out_of_range};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (round)
|
||||
{
|
||||
significand += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return {first, std::errc::invalid_argument};
|
||||
}
|
||||
|
||||
// Finally we get the exponent
|
||||
constexpr std::size_t exponent_buffer_size = 6; // Float128 min exp is −16382
|
||||
char exponent_buffer[exponent_buffer_size] {};
|
||||
Integer significand_digits = i;
|
||||
i = 0;
|
||||
|
||||
// Get the sign first
|
||||
if (*next == '-')
|
||||
{
|
||||
exponent_buffer[i] = *next;
|
||||
++next;
|
||||
++i;
|
||||
}
|
||||
else if (*next == '+')
|
||||
{
|
||||
++next;
|
||||
}
|
||||
|
||||
// Next strip any leading zeros
|
||||
while (*next == '0')
|
||||
{
|
||||
++next;
|
||||
}
|
||||
|
||||
// Process the significant values
|
||||
while (is_integer_char(*next) && next != last && i < exponent_buffer_size)
|
||||
{
|
||||
exponent_buffer[i] = *next;
|
||||
++next;
|
||||
++i;
|
||||
}
|
||||
|
||||
// If the exponent can't fit in the buffer the number is not representable
|
||||
if (next != last && i == exponent_buffer_size)
|
||||
{
|
||||
return {next, std::errc::result_out_of_range};
|
||||
}
|
||||
|
||||
// If the exponent was e+00 or e-00
|
||||
if (i == 0 || (i == 1 && exponent_buffer[0] == '-'))
|
||||
{
|
||||
if (fractional)
|
||||
{
|
||||
exponent = static_cast<Integer>(dot_position) - significand_digits;
|
||||
}
|
||||
else
|
||||
{
|
||||
exponent = extra_zeros;
|
||||
}
|
||||
|
||||
return {next, std::errc()};
|
||||
}
|
||||
|
||||
const auto r = from_chars(exponent_buffer, exponent_buffer + i, exponent);
|
||||
|
||||
exponent += leading_zero_powers;
|
||||
|
||||
switch (r.ec)
|
||||
{
|
||||
case std::errc::invalid_argument:
|
||||
return {first, std::errc::invalid_argument};
|
||||
case std::errc::result_out_of_range:
|
||||
return {next, std::errc::result_out_of_range};
|
||||
default:
|
||||
if (fractional)
|
||||
{
|
||||
// Need to take the offset from 1.xxx because compute_floatXXX assumes the significand is an integer
|
||||
// so the exponent is off by the number of digits in the significand - 1
|
||||
if (fmt == chars_format::hex)
|
||||
{
|
||||
// In hex the number of digits parsed is possibly less than the number of digits in base10
|
||||
exponent -= num_digits(significand) - dot_position;
|
||||
}
|
||||
else
|
||||
{
|
||||
exponent -= significand_digits - dot_position;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exponent += extra_zeros;
|
||||
}
|
||||
return {next, std::errc()};
|
||||
}
|
||||
}
|
||||
|
||||
}}}}} // Namespaces
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP
|
||||
+667
@@ -0,0 +1,667 @@
|
||||
// Copyright 2020-2023 Daniel Lemire
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_SIGNIFICAND_TABLES_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_DETAIL_SIGNIFICAND_TABLES_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// The significand of a floating point number is often referred to as the mantissa.
|
||||
// Using the term mantissa is discouraged by IEEE 1516
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
|
||||
|
||||
// The significands of powers of ten from -308 to 308, extended out to sixty four
|
||||
// bits. The array contains the powers of ten approximated
|
||||
// as a 64-bit significand. It goes from 10^BOOST_CHARCONV_FASTFLOAT_SMALLEST_POWER to
|
||||
// 10^BOOST_CHARCONV_FASTFLOAT_LARGEST_POWER (inclusively).
|
||||
// The significand is truncated, and never rounded up.
|
||||
// Uses about 5KB.
|
||||
static constexpr std::uint64_t significand_64[] = {
|
||||
0xa5ced43b7e3e9188, 0xcf42894a5dce35ea,
|
||||
0x818995ce7aa0e1b2, 0xa1ebfb4219491a1f,
|
||||
0xca66fa129f9b60a6, 0xfd00b897478238d0,
|
||||
0x9e20735e8cb16382, 0xc5a890362fddbc62,
|
||||
0xf712b443bbd52b7b, 0x9a6bb0aa55653b2d,
|
||||
0xc1069cd4eabe89f8, 0xf148440a256e2c76,
|
||||
0x96cd2a865764dbca, 0xbc807527ed3e12bc,
|
||||
0xeba09271e88d976b, 0x93445b8731587ea3,
|
||||
0xb8157268fdae9e4c, 0xe61acf033d1a45df,
|
||||
0x8fd0c16206306bab, 0xb3c4f1ba87bc8696,
|
||||
0xe0b62e2929aba83c, 0x8c71dcd9ba0b4925,
|
||||
0xaf8e5410288e1b6f, 0xdb71e91432b1a24a,
|
||||
0x892731ac9faf056e, 0xab70fe17c79ac6ca,
|
||||
0xd64d3d9db981787d, 0x85f0468293f0eb4e,
|
||||
0xa76c582338ed2621, 0xd1476e2c07286faa,
|
||||
0x82cca4db847945ca, 0xa37fce126597973c,
|
||||
0xcc5fc196fefd7d0c, 0xff77b1fcbebcdc4f,
|
||||
0x9faacf3df73609b1, 0xc795830d75038c1d,
|
||||
0xf97ae3d0d2446f25, 0x9becce62836ac577,
|
||||
0xc2e801fb244576d5, 0xf3a20279ed56d48a,
|
||||
0x9845418c345644d6, 0xbe5691ef416bd60c,
|
||||
0xedec366b11c6cb8f, 0x94b3a202eb1c3f39,
|
||||
0xb9e08a83a5e34f07, 0xe858ad248f5c22c9,
|
||||
0x91376c36d99995be, 0xb58547448ffffb2d,
|
||||
0xe2e69915b3fff9f9, 0x8dd01fad907ffc3b,
|
||||
0xb1442798f49ffb4a, 0xdd95317f31c7fa1d,
|
||||
0x8a7d3eef7f1cfc52, 0xad1c8eab5ee43b66,
|
||||
0xd863b256369d4a40, 0x873e4f75e2224e68,
|
||||
0xa90de3535aaae202, 0xd3515c2831559a83,
|
||||
0x8412d9991ed58091, 0xa5178fff668ae0b6,
|
||||
0xce5d73ff402d98e3, 0x80fa687f881c7f8e,
|
||||
0xa139029f6a239f72, 0xc987434744ac874e,
|
||||
0xfbe9141915d7a922, 0x9d71ac8fada6c9b5,
|
||||
0xc4ce17b399107c22, 0xf6019da07f549b2b,
|
||||
0x99c102844f94e0fb, 0xc0314325637a1939,
|
||||
0xf03d93eebc589f88, 0x96267c7535b763b5,
|
||||
0xbbb01b9283253ca2, 0xea9c227723ee8bcb,
|
||||
0x92a1958a7675175f, 0xb749faed14125d36,
|
||||
0xe51c79a85916f484, 0x8f31cc0937ae58d2,
|
||||
0xb2fe3f0b8599ef07, 0xdfbdcece67006ac9,
|
||||
0x8bd6a141006042bd, 0xaecc49914078536d,
|
||||
0xda7f5bf590966848, 0x888f99797a5e012d,
|
||||
0xaab37fd7d8f58178, 0xd5605fcdcf32e1d6,
|
||||
0x855c3be0a17fcd26, 0xa6b34ad8c9dfc06f,
|
||||
0xd0601d8efc57b08b, 0x823c12795db6ce57,
|
||||
0xa2cb1717b52481ed, 0xcb7ddcdda26da268,
|
||||
0xfe5d54150b090b02, 0x9efa548d26e5a6e1,
|
||||
0xc6b8e9b0709f109a, 0xf867241c8cc6d4c0,
|
||||
0x9b407691d7fc44f8, 0xc21094364dfb5636,
|
||||
0xf294b943e17a2bc4, 0x979cf3ca6cec5b5a,
|
||||
0xbd8430bd08277231, 0xece53cec4a314ebd,
|
||||
0x940f4613ae5ed136, 0xb913179899f68584,
|
||||
0xe757dd7ec07426e5, 0x9096ea6f3848984f,
|
||||
0xb4bca50b065abe63, 0xe1ebce4dc7f16dfb,
|
||||
0x8d3360f09cf6e4bd, 0xb080392cc4349dec,
|
||||
0xdca04777f541c567, 0x89e42caaf9491b60,
|
||||
0xac5d37d5b79b6239, 0xd77485cb25823ac7,
|
||||
0x86a8d39ef77164bc, 0xa8530886b54dbdeb,
|
||||
0xd267caa862a12d66, 0x8380dea93da4bc60,
|
||||
0xa46116538d0deb78, 0xcd795be870516656,
|
||||
0x806bd9714632dff6, 0xa086cfcd97bf97f3,
|
||||
0xc8a883c0fdaf7df0, 0xfad2a4b13d1b5d6c,
|
||||
0x9cc3a6eec6311a63, 0xc3f490aa77bd60fc,
|
||||
0xf4f1b4d515acb93b, 0x991711052d8bf3c5,
|
||||
0xbf5cd54678eef0b6, 0xef340a98172aace4,
|
||||
0x9580869f0e7aac0e, 0xbae0a846d2195712,
|
||||
0xe998d258869facd7, 0x91ff83775423cc06,
|
||||
0xb67f6455292cbf08, 0xe41f3d6a7377eeca,
|
||||
0x8e938662882af53e, 0xb23867fb2a35b28d,
|
||||
0xdec681f9f4c31f31, 0x8b3c113c38f9f37e,
|
||||
0xae0b158b4738705e, 0xd98ddaee19068c76,
|
||||
0x87f8a8d4cfa417c9, 0xa9f6d30a038d1dbc,
|
||||
0xd47487cc8470652b, 0x84c8d4dfd2c63f3b,
|
||||
0xa5fb0a17c777cf09, 0xcf79cc9db955c2cc,
|
||||
0x81ac1fe293d599bf, 0xa21727db38cb002f,
|
||||
0xca9cf1d206fdc03b, 0xfd442e4688bd304a,
|
||||
0x9e4a9cec15763e2e, 0xc5dd44271ad3cdba,
|
||||
0xf7549530e188c128, 0x9a94dd3e8cf578b9,
|
||||
0xc13a148e3032d6e7, 0xf18899b1bc3f8ca1,
|
||||
0x96f5600f15a7b7e5, 0xbcb2b812db11a5de,
|
||||
0xebdf661791d60f56, 0x936b9fcebb25c995,
|
||||
0xb84687c269ef3bfb, 0xe65829b3046b0afa,
|
||||
0x8ff71a0fe2c2e6dc, 0xb3f4e093db73a093,
|
||||
0xe0f218b8d25088b8, 0x8c974f7383725573,
|
||||
0xafbd2350644eeacf, 0xdbac6c247d62a583,
|
||||
0x894bc396ce5da772, 0xab9eb47c81f5114f,
|
||||
0xd686619ba27255a2, 0x8613fd0145877585,
|
||||
0xa798fc4196e952e7, 0xd17f3b51fca3a7a0,
|
||||
0x82ef85133de648c4, 0xa3ab66580d5fdaf5,
|
||||
0xcc963fee10b7d1b3, 0xffbbcfe994e5c61f,
|
||||
0x9fd561f1fd0f9bd3, 0xc7caba6e7c5382c8,
|
||||
0xf9bd690a1b68637b, 0x9c1661a651213e2d,
|
||||
0xc31bfa0fe5698db8, 0xf3e2f893dec3f126,
|
||||
0x986ddb5c6b3a76b7, 0xbe89523386091465,
|
||||
0xee2ba6c0678b597f, 0x94db483840b717ef,
|
||||
0xba121a4650e4ddeb, 0xe896a0d7e51e1566,
|
||||
0x915e2486ef32cd60, 0xb5b5ada8aaff80b8,
|
||||
0xe3231912d5bf60e6, 0x8df5efabc5979c8f,
|
||||
0xb1736b96b6fd83b3, 0xddd0467c64bce4a0,
|
||||
0x8aa22c0dbef60ee4, 0xad4ab7112eb3929d,
|
||||
0xd89d64d57a607744, 0x87625f056c7c4a8b,
|
||||
0xa93af6c6c79b5d2d, 0xd389b47879823479,
|
||||
0x843610cb4bf160cb, 0xa54394fe1eedb8fe,
|
||||
0xce947a3da6a9273e, 0x811ccc668829b887,
|
||||
0xa163ff802a3426a8, 0xc9bcff6034c13052,
|
||||
0xfc2c3f3841f17c67, 0x9d9ba7832936edc0,
|
||||
0xc5029163f384a931, 0xf64335bcf065d37d,
|
||||
0x99ea0196163fa42e, 0xc06481fb9bcf8d39,
|
||||
0xf07da27a82c37088, 0x964e858c91ba2655,
|
||||
0xbbe226efb628afea, 0xeadab0aba3b2dbe5,
|
||||
0x92c8ae6b464fc96f, 0xb77ada0617e3bbcb,
|
||||
0xe55990879ddcaabd, 0x8f57fa54c2a9eab6,
|
||||
0xb32df8e9f3546564, 0xdff9772470297ebd,
|
||||
0x8bfbea76c619ef36, 0xaefae51477a06b03,
|
||||
0xdab99e59958885c4, 0x88b402f7fd75539b,
|
||||
0xaae103b5fcd2a881, 0xd59944a37c0752a2,
|
||||
0x857fcae62d8493a5, 0xa6dfbd9fb8e5b88e,
|
||||
0xd097ad07a71f26b2, 0x825ecc24c873782f,
|
||||
0xa2f67f2dfa90563b, 0xcbb41ef979346bca,
|
||||
0xfea126b7d78186bc, 0x9f24b832e6b0f436,
|
||||
0xc6ede63fa05d3143, 0xf8a95fcf88747d94,
|
||||
0x9b69dbe1b548ce7c, 0xc24452da229b021b,
|
||||
0xf2d56790ab41c2a2, 0x97c560ba6b0919a5,
|
||||
0xbdb6b8e905cb600f, 0xed246723473e3813,
|
||||
0x9436c0760c86e30b, 0xb94470938fa89bce,
|
||||
0xe7958cb87392c2c2, 0x90bd77f3483bb9b9,
|
||||
0xb4ecd5f01a4aa828, 0xe2280b6c20dd5232,
|
||||
0x8d590723948a535f, 0xb0af48ec79ace837,
|
||||
0xdcdb1b2798182244, 0x8a08f0f8bf0f156b,
|
||||
0xac8b2d36eed2dac5, 0xd7adf884aa879177,
|
||||
0x86ccbb52ea94baea, 0xa87fea27a539e9a5,
|
||||
0xd29fe4b18e88640e, 0x83a3eeeef9153e89,
|
||||
0xa48ceaaab75a8e2b, 0xcdb02555653131b6,
|
||||
0x808e17555f3ebf11, 0xa0b19d2ab70e6ed6,
|
||||
0xc8de047564d20a8b, 0xfb158592be068d2e,
|
||||
0x9ced737bb6c4183d, 0xc428d05aa4751e4c,
|
||||
0xf53304714d9265df, 0x993fe2c6d07b7fab,
|
||||
0xbf8fdb78849a5f96, 0xef73d256a5c0f77c,
|
||||
0x95a8637627989aad, 0xbb127c53b17ec159,
|
||||
0xe9d71b689dde71af, 0x9226712162ab070d,
|
||||
0xb6b00d69bb55c8d1, 0xe45c10c42a2b3b05,
|
||||
0x8eb98a7a9a5b04e3, 0xb267ed1940f1c61c,
|
||||
0xdf01e85f912e37a3, 0x8b61313bbabce2c6,
|
||||
0xae397d8aa96c1b77, 0xd9c7dced53c72255,
|
||||
0x881cea14545c7575, 0xaa242499697392d2,
|
||||
0xd4ad2dbfc3d07787, 0x84ec3c97da624ab4,
|
||||
0xa6274bbdd0fadd61, 0xcfb11ead453994ba,
|
||||
0x81ceb32c4b43fcf4, 0xa2425ff75e14fc31,
|
||||
0xcad2f7f5359a3b3e, 0xfd87b5f28300ca0d,
|
||||
0x9e74d1b791e07e48, 0xc612062576589dda,
|
||||
0xf79687aed3eec551, 0x9abe14cd44753b52,
|
||||
0xc16d9a0095928a27, 0xf1c90080baf72cb1,
|
||||
0x971da05074da7bee, 0xbce5086492111aea,
|
||||
0xec1e4a7db69561a5, 0x9392ee8e921d5d07,
|
||||
0xb877aa3236a4b449, 0xe69594bec44de15b,
|
||||
0x901d7cf73ab0acd9, 0xb424dc35095cd80f,
|
||||
0xe12e13424bb40e13, 0x8cbccc096f5088cb,
|
||||
0xafebff0bcb24aafe, 0xdbe6fecebdedd5be,
|
||||
0x89705f4136b4a597, 0xabcc77118461cefc,
|
||||
0xd6bf94d5e57a42bc, 0x8637bd05af6c69b5,
|
||||
0xa7c5ac471b478423, 0xd1b71758e219652b,
|
||||
0x83126e978d4fdf3b, 0xa3d70a3d70a3d70a,
|
||||
0xcccccccccccccccc, 0x8000000000000000,
|
||||
0xa000000000000000, 0xc800000000000000,
|
||||
0xfa00000000000000, 0x9c40000000000000,
|
||||
0xc350000000000000, 0xf424000000000000,
|
||||
0x9896800000000000, 0xbebc200000000000,
|
||||
0xee6b280000000000, 0x9502f90000000000,
|
||||
0xba43b74000000000, 0xe8d4a51000000000,
|
||||
0x9184e72a00000000, 0xb5e620f480000000,
|
||||
0xe35fa931a0000000, 0x8e1bc9bf04000000,
|
||||
0xb1a2bc2ec5000000, 0xde0b6b3a76400000,
|
||||
0x8ac7230489e80000, 0xad78ebc5ac620000,
|
||||
0xd8d726b7177a8000, 0x878678326eac9000,
|
||||
0xa968163f0a57b400, 0xd3c21bcecceda100,
|
||||
0x84595161401484a0, 0xa56fa5b99019a5c8,
|
||||
0xcecb8f27f4200f3a, 0x813f3978f8940984,
|
||||
0xa18f07d736b90be5, 0xc9f2c9cd04674ede,
|
||||
0xfc6f7c4045812296, 0x9dc5ada82b70b59d,
|
||||
0xc5371912364ce305, 0xf684df56c3e01bc6,
|
||||
0x9a130b963a6c115c, 0xc097ce7bc90715b3,
|
||||
0xf0bdc21abb48db20, 0x96769950b50d88f4,
|
||||
0xbc143fa4e250eb31, 0xeb194f8e1ae525fd,
|
||||
0x92efd1b8d0cf37be, 0xb7abc627050305ad,
|
||||
0xe596b7b0c643c719, 0x8f7e32ce7bea5c6f,
|
||||
0xb35dbf821ae4f38b, 0xe0352f62a19e306e,
|
||||
0x8c213d9da502de45, 0xaf298d050e4395d6,
|
||||
0xdaf3f04651d47b4c, 0x88d8762bf324cd0f,
|
||||
0xab0e93b6efee0053, 0xd5d238a4abe98068,
|
||||
0x85a36366eb71f041, 0xa70c3c40a64e6c51,
|
||||
0xd0cf4b50cfe20765, 0x82818f1281ed449f,
|
||||
0xa321f2d7226895c7, 0xcbea6f8ceb02bb39,
|
||||
0xfee50b7025c36a08, 0x9f4f2726179a2245,
|
||||
0xc722f0ef9d80aad6, 0xf8ebad2b84e0d58b,
|
||||
0x9b934c3b330c8577, 0xc2781f49ffcfa6d5,
|
||||
0xf316271c7fc3908a, 0x97edd871cfda3a56,
|
||||
0xbde94e8e43d0c8ec, 0xed63a231d4c4fb27,
|
||||
0x945e455f24fb1cf8, 0xb975d6b6ee39e436,
|
||||
0xe7d34c64a9c85d44, 0x90e40fbeea1d3a4a,
|
||||
0xb51d13aea4a488dd, 0xe264589a4dcdab14,
|
||||
0x8d7eb76070a08aec, 0xb0de65388cc8ada8,
|
||||
0xdd15fe86affad912, 0x8a2dbf142dfcc7ab,
|
||||
0xacb92ed9397bf996, 0xd7e77a8f87daf7fb,
|
||||
0x86f0ac99b4e8dafd, 0xa8acd7c0222311bc,
|
||||
0xd2d80db02aabd62b, 0x83c7088e1aab65db,
|
||||
0xa4b8cab1a1563f52, 0xcde6fd5e09abcf26,
|
||||
0x80b05e5ac60b6178, 0xa0dc75f1778e39d6,
|
||||
0xc913936dd571c84c, 0xfb5878494ace3a5f,
|
||||
0x9d174b2dcec0e47b, 0xc45d1df942711d9a,
|
||||
0xf5746577930d6500, 0x9968bf6abbe85f20,
|
||||
0xbfc2ef456ae276e8, 0xefb3ab16c59b14a2,
|
||||
0x95d04aee3b80ece5, 0xbb445da9ca61281f,
|
||||
0xea1575143cf97226, 0x924d692ca61be758,
|
||||
0xb6e0c377cfa2e12e, 0xe498f455c38b997a,
|
||||
0x8edf98b59a373fec, 0xb2977ee300c50fe7,
|
||||
0xdf3d5e9bc0f653e1, 0x8b865b215899f46c,
|
||||
0xae67f1e9aec07187, 0xda01ee641a708de9,
|
||||
0x884134fe908658b2, 0xaa51823e34a7eede,
|
||||
0xd4e5e2cdc1d1ea96, 0x850fadc09923329e,
|
||||
0xa6539930bf6bff45, 0xcfe87f7cef46ff16,
|
||||
0x81f14fae158c5f6e, 0xa26da3999aef7749,
|
||||
0xcb090c8001ab551c, 0xfdcb4fa002162a63,
|
||||
0x9e9f11c4014dda7e, 0xc646d63501a1511d,
|
||||
0xf7d88bc24209a565, 0x9ae757596946075f,
|
||||
0xc1a12d2fc3978937, 0xf209787bb47d6b84,
|
||||
0x9745eb4d50ce6332, 0xbd176620a501fbff,
|
||||
0xec5d3fa8ce427aff, 0x93ba47c980e98cdf,
|
||||
0xb8a8d9bbe123f017, 0xe6d3102ad96cec1d,
|
||||
0x9043ea1ac7e41392, 0xb454e4a179dd1877,
|
||||
0xe16a1dc9d8545e94, 0x8ce2529e2734bb1d,
|
||||
0xb01ae745b101e9e4, 0xdc21a1171d42645d,
|
||||
0x899504ae72497eba, 0xabfa45da0edbde69,
|
||||
0xd6f8d7509292d603, 0x865b86925b9bc5c2,
|
||||
0xa7f26836f282b732, 0xd1ef0244af2364ff,
|
||||
0x8335616aed761f1f, 0xa402b9c5a8d3a6e7,
|
||||
0xcd036837130890a1, 0x802221226be55a64,
|
||||
0xa02aa96b06deb0fd, 0xc83553c5c8965d3d,
|
||||
0xfa42a8b73abbf48c, 0x9c69a97284b578d7,
|
||||
0xc38413cf25e2d70d, 0xf46518c2ef5b8cd1,
|
||||
0x98bf2f79d5993802, 0xbeeefb584aff8603,
|
||||
0xeeaaba2e5dbf6784, 0x952ab45cfa97a0b2,
|
||||
0xba756174393d88df, 0xe912b9d1478ceb17,
|
||||
0x91abb422ccb812ee, 0xb616a12b7fe617aa,
|
||||
0xe39c49765fdf9d94, 0x8e41ade9fbebc27d,
|
||||
0xb1d219647ae6b31c, 0xde469fbd99a05fe3,
|
||||
0x8aec23d680043bee, 0xada72ccc20054ae9,
|
||||
0xd910f7ff28069da4, 0x87aa9aff79042286,
|
||||
0xa99541bf57452b28, 0xd3fa922f2d1675f2,
|
||||
0x847c9b5d7c2e09b7, 0xa59bc234db398c25,
|
||||
0xcf02b2c21207ef2e, 0x8161afb94b44f57d,
|
||||
0xa1ba1ba79e1632dc, 0xca28a291859bbf93,
|
||||
0xfcb2cb35e702af78, 0x9defbf01b061adab,
|
||||
0xc56baec21c7a1916, 0xf6c69a72a3989f5b,
|
||||
0x9a3c2087a63f6399, 0xc0cb28a98fcf3c7f,
|
||||
0xf0fdf2d3f3c30b9f, 0x969eb7c47859e743,
|
||||
0xbc4665b596706114, 0xeb57ff22fc0c7959,
|
||||
0x9316ff75dd87cbd8, 0xb7dcbf5354e9bece,
|
||||
0xe5d3ef282a242e81, 0x8fa475791a569d10,
|
||||
0xb38d92d760ec4455, 0xe070f78d3927556a,
|
||||
0x8c469ab843b89562, 0xaf58416654a6babb,
|
||||
0xdb2e51bfe9d0696a, 0x88fcf317f22241e2,
|
||||
0xab3c2fddeeaad25a, 0xd60b3bd56a5586f1,
|
||||
0x85c7056562757456, 0xa738c6bebb12d16c,
|
||||
0xd106f86e69d785c7, 0x82a45b450226b39c,
|
||||
0xa34d721642b06084, 0xcc20ce9bd35c78a5,
|
||||
0xff290242c83396ce, 0x9f79a169bd203e41,
|
||||
0xc75809c42c684dd1, 0xf92e0c3537826145,
|
||||
0x9bbcc7a142b17ccb, 0xc2abf989935ddbfe,
|
||||
0xf356f7ebf83552fe, 0x98165af37b2153de,
|
||||
0xbe1bf1b059e9a8d6, 0xeda2ee1c7064130c,
|
||||
0x9485d4d1c63e8be7, 0xb9a74a0637ce2ee1,
|
||||
0xe8111c87c5c1ba99, 0x910ab1d4db9914a0,
|
||||
0xb54d5e4a127f59c8, 0xe2a0b5dc971f303a,
|
||||
0x8da471a9de737e24, 0xb10d8e1456105dad,
|
||||
0xdd50f1996b947518, 0x8a5296ffe33cc92f,
|
||||
0xace73cbfdc0bfb7b, 0xd8210befd30efa5a,
|
||||
0x8714a775e3e95c78, 0xa8d9d1535ce3b396,
|
||||
0xd31045a8341ca07c, 0x83ea2b892091e44d,
|
||||
0xa4e4b66b68b65d60, 0xce1de40642e3f4b9,
|
||||
0x80d2ae83e9ce78f3, 0xa1075a24e4421730,
|
||||
0xc94930ae1d529cfc, 0xfb9b7cd9a4a7443c,
|
||||
0x9d412e0806e88aa5, 0xc491798a08a2ad4e,
|
||||
0xf5b5d7ec8acb58a2, 0x9991a6f3d6bf1765,
|
||||
0xbff610b0cc6edd3f, 0xeff394dcff8a948e,
|
||||
0x95f83d0a1fb69cd9, 0xbb764c4ca7a4440f,
|
||||
0xea53df5fd18d5513, 0x92746b9be2f8552c,
|
||||
0xb7118682dbb66a77, 0xe4d5e82392a40515,
|
||||
0x8f05b1163ba6832d, 0xb2c71d5bca9023f8,
|
||||
0xdf78e4b2bd342cf6, 0x8bab8eefb6409c1a,
|
||||
0xae9672aba3d0c320, 0xda3c0f568cc4f3e8,
|
||||
0x8865899617fb1871, 0xaa7eebfb9df9de8d,
|
||||
0xd51ea6fa85785631, 0x8533285c936b35de,
|
||||
0xa67ff273b8460356, 0xd01fef10a657842c,
|
||||
0x8213f56a67f6b29b, 0xa298f2c501f45f42,
|
||||
0xcb3f2f7642717713, 0xfe0efb53d30dd4d7,
|
||||
0x9ec95d1463e8a506, 0xc67bb4597ce2ce48,
|
||||
0xf81aa16fdc1b81da, 0x9b10a4e5e9913128,
|
||||
0xc1d4ce1f63f57d72, 0xf24a01a73cf2dccf,
|
||||
0x976e41088617ca01, 0xbd49d14aa79dbc82,
|
||||
0xec9c459d51852ba2, 0x93e1ab8252f33b45,
|
||||
0xb8da1662e7b00a17, 0xe7109bfba19c0c9d,
|
||||
0x906a617d450187e2, 0xb484f9dc9641e9da,
|
||||
0xe1a63853bbd26451, 0x8d07e33455637eb2,
|
||||
0xb049dc016abc5e5f, 0xdc5c5301c56b75f7,
|
||||
0x89b9b3e11b6329ba, 0xac2820d9623bf429,
|
||||
0xd732290fbacaf133, 0x867f59a9d4bed6c0,
|
||||
0xa81f301449ee8c70, 0xd226fc195c6a2f8c,
|
||||
0x83585d8fd9c25db7, 0xa42e74f3d032f525,
|
||||
0xcd3a1230c43fb26f, 0x80444b5e7aa7cf85,
|
||||
0xa0555e361951c366, 0xc86ab5c39fa63440,
|
||||
0xfa856334878fc150, 0x9c935e00d4b9d8d2,
|
||||
0xc3b8358109e84f07, 0xf4a642e14c6262c8,
|
||||
0x98e7e9cccfbd7dbd, 0xbf21e44003acdd2c,
|
||||
0xeeea5d5004981478, 0x95527a5202df0ccb,
|
||||
0xbaa718e68396cffd, 0xe950df20247c83fd,
|
||||
0x91d28b7416cdd27e, 0xb6472e511c81471d,
|
||||
0xe3d8f9e563a198e5, 0x8e679c2f5e44ff8f
|
||||
};
|
||||
|
||||
// A complement to significand_64
|
||||
// complete to a 128-bit significand.
|
||||
// Uses about 5KB but is rarely accessed.
|
||||
static constexpr std::uint64_t significand_128[] = {
|
||||
0x419ea3bd35385e2d, 0x52064cac828675b9,
|
||||
0x7343efebd1940993, 0x1014ebe6c5f90bf8,
|
||||
0xd41a26e077774ef6, 0x8920b098955522b4,
|
||||
0x55b46e5f5d5535b0, 0xeb2189f734aa831d,
|
||||
0xa5e9ec7501d523e4, 0x47b233c92125366e,
|
||||
0x999ec0bb696e840a, 0xc00670ea43ca250d,
|
||||
0x380406926a5e5728, 0xc605083704f5ecf2,
|
||||
0xf7864a44c633682e, 0x7ab3ee6afbe0211d,
|
||||
0x5960ea05bad82964, 0x6fb92487298e33bd,
|
||||
0xa5d3b6d479f8e056, 0x8f48a4899877186c,
|
||||
0x331acdabfe94de87, 0x9ff0c08b7f1d0b14,
|
||||
0x7ecf0ae5ee44dd9, 0xc9e82cd9f69d6150,
|
||||
0xbe311c083a225cd2, 0x6dbd630a48aaf406,
|
||||
0x92cbbccdad5b108, 0x25bbf56008c58ea5,
|
||||
0xaf2af2b80af6f24e, 0x1af5af660db4aee1,
|
||||
0x50d98d9fc890ed4d, 0xe50ff107bab528a0,
|
||||
0x1e53ed49a96272c8, 0x25e8e89c13bb0f7a,
|
||||
0x77b191618c54e9ac, 0xd59df5b9ef6a2417,
|
||||
0x4b0573286b44ad1d, 0x4ee367f9430aec32,
|
||||
0x229c41f793cda73f, 0x6b43527578c1110f,
|
||||
0x830a13896b78aaa9, 0x23cc986bc656d553,
|
||||
0x2cbfbe86b7ec8aa8, 0x7bf7d71432f3d6a9,
|
||||
0xdaf5ccd93fb0cc53, 0xd1b3400f8f9cff68,
|
||||
0x23100809b9c21fa1, 0xabd40a0c2832a78a,
|
||||
0x16c90c8f323f516c, 0xae3da7d97f6792e3,
|
||||
0x99cd11cfdf41779c, 0x40405643d711d583,
|
||||
0x482835ea666b2572, 0xda3243650005eecf,
|
||||
0x90bed43e40076a82, 0x5a7744a6e804a291,
|
||||
0x711515d0a205cb36, 0xd5a5b44ca873e03,
|
||||
0xe858790afe9486c2, 0x626e974dbe39a872,
|
||||
0xfb0a3d212dc8128f, 0x7ce66634bc9d0b99,
|
||||
0x1c1fffc1ebc44e80, 0xa327ffb266b56220,
|
||||
0x4bf1ff9f0062baa8, 0x6f773fc3603db4a9,
|
||||
0xcb550fb4384d21d3, 0x7e2a53a146606a48,
|
||||
0x2eda7444cbfc426d, 0xfa911155fefb5308,
|
||||
0x793555ab7eba27ca, 0x4bc1558b2f3458de,
|
||||
0x9eb1aaedfb016f16, 0x465e15a979c1cadc,
|
||||
0xbfacd89ec191ec9, 0xcef980ec671f667b,
|
||||
0x82b7e12780e7401a, 0xd1b2ecb8b0908810,
|
||||
0x861fa7e6dcb4aa15, 0x67a791e093e1d49a,
|
||||
0xe0c8bb2c5c6d24e0, 0x58fae9f773886e18,
|
||||
0xaf39a475506a899e, 0x6d8406c952429603,
|
||||
0xc8e5087ba6d33b83, 0xfb1e4a9a90880a64,
|
||||
0x5cf2eea09a55067f, 0xf42faa48c0ea481e,
|
||||
0xf13b94daf124da26, 0x76c53d08d6b70858,
|
||||
0x54768c4b0c64ca6e, 0xa9942f5dcf7dfd09,
|
||||
0xd3f93b35435d7c4c, 0xc47bc5014a1a6daf,
|
||||
0x359ab6419ca1091b, 0xc30163d203c94b62,
|
||||
0x79e0de63425dcf1d, 0x985915fc12f542e4,
|
||||
0x3e6f5b7b17b2939d, 0xa705992ceecf9c42,
|
||||
0x50c6ff782a838353, 0xa4f8bf5635246428,
|
||||
0x871b7795e136be99, 0x28e2557b59846e3f,
|
||||
0x331aeada2fe589cf, 0x3ff0d2c85def7621,
|
||||
0xfed077a756b53a9, 0xd3e8495912c62894,
|
||||
0x64712dd7abbbd95c, 0xbd8d794d96aacfb3,
|
||||
0xecf0d7a0fc5583a0, 0xf41686c49db57244,
|
||||
0x311c2875c522ced5, 0x7d633293366b828b,
|
||||
0xae5dff9c02033197, 0xd9f57f830283fdfc,
|
||||
0xd072df63c324fd7b, 0x4247cb9e59f71e6d,
|
||||
0x52d9be85f074e608, 0x67902e276c921f8b,
|
||||
0xba1cd8a3db53b6, 0x80e8a40eccd228a4,
|
||||
0x6122cd128006b2cd, 0x796b805720085f81,
|
||||
0xcbe3303674053bb0, 0xbedbfc4411068a9c,
|
||||
0xee92fb5515482d44, 0x751bdd152d4d1c4a,
|
||||
0xd262d45a78a0635d, 0x86fb897116c87c34,
|
||||
0xd45d35e6ae3d4da0, 0x8974836059cca109,
|
||||
0x2bd1a438703fc94b, 0x7b6306a34627ddcf,
|
||||
0x1a3bc84c17b1d542, 0x20caba5f1d9e4a93,
|
||||
0x547eb47b7282ee9c, 0xe99e619a4f23aa43,
|
||||
0x6405fa00e2ec94d4, 0xde83bc408dd3dd04,
|
||||
0x9624ab50b148d445, 0x3badd624dd9b0957,
|
||||
0xe54ca5d70a80e5d6, 0x5e9fcf4ccd211f4c,
|
||||
0x7647c3200069671f, 0x29ecd9f40041e073,
|
||||
0xf468107100525890, 0x7182148d4066eeb4,
|
||||
0xc6f14cd848405530, 0xb8ada00e5a506a7c,
|
||||
0xa6d90811f0e4851c, 0x908f4a166d1da663,
|
||||
0x9a598e4e043287fe, 0x40eff1e1853f29fd,
|
||||
0xd12bee59e68ef47c, 0x82bb74f8301958ce,
|
||||
0xe36a52363c1faf01, 0xdc44e6c3cb279ac1,
|
||||
0x29ab103a5ef8c0b9, 0x7415d448f6b6f0e7,
|
||||
0x111b495b3464ad21, 0xcab10dd900beec34,
|
||||
0x3d5d514f40eea742, 0xcb4a5a3112a5112,
|
||||
0x47f0e785eaba72ab, 0x59ed216765690f56,
|
||||
0x306869c13ec3532c, 0x1e414218c73a13fb,
|
||||
0xe5d1929ef90898fa, 0xdf45f746b74abf39,
|
||||
0x6b8bba8c328eb783, 0x66ea92f3f326564,
|
||||
0xc80a537b0efefebd, 0xbd06742ce95f5f36,
|
||||
0x2c48113823b73704, 0xf75a15862ca504c5,
|
||||
0x9a984d73dbe722fb, 0xc13e60d0d2e0ebba,
|
||||
0x318df905079926a8, 0xfdf17746497f7052,
|
||||
0xfeb6ea8bedefa633, 0xfe64a52ee96b8fc0,
|
||||
0x3dfdce7aa3c673b0, 0x6bea10ca65c084e,
|
||||
0x486e494fcff30a62, 0x5a89dba3c3efccfa,
|
||||
0xf89629465a75e01c, 0xf6bbb397f1135823,
|
||||
0x746aa07ded582e2c, 0xa8c2a44eb4571cdc,
|
||||
0x92f34d62616ce413, 0x77b020baf9c81d17,
|
||||
0xace1474dc1d122e, 0xd819992132456ba,
|
||||
0x10e1fff697ed6c69, 0xca8d3ffa1ef463c1,
|
||||
0xbd308ff8a6b17cb2, 0xac7cb3f6d05ddbde,
|
||||
0x6bcdf07a423aa96b, 0x86c16c98d2c953c6,
|
||||
0xe871c7bf077ba8b7, 0x11471cd764ad4972,
|
||||
0xd598e40d3dd89bcf, 0x4aff1d108d4ec2c3,
|
||||
0xcedf722a585139ba, 0xc2974eb4ee658828,
|
||||
0x733d226229feea32, 0x806357d5a3f525f,
|
||||
0xca07c2dcb0cf26f7, 0xfc89b393dd02f0b5,
|
||||
0xbbac2078d443ace2, 0xd54b944b84aa4c0d,
|
||||
0xa9e795e65d4df11, 0x4d4617b5ff4a16d5,
|
||||
0x504bced1bf8e4e45, 0xe45ec2862f71e1d6,
|
||||
0x5d767327bb4e5a4c, 0x3a6a07f8d510f86f,
|
||||
0x890489f70a55368b, 0x2b45ac74ccea842e,
|
||||
0x3b0b8bc90012929d, 0x9ce6ebb40173744,
|
||||
0xcc420a6a101d0515, 0x9fa946824a12232d,
|
||||
0x47939822dc96abf9, 0x59787e2b93bc56f7,
|
||||
0x57eb4edb3c55b65a, 0xede622920b6b23f1,
|
||||
0xe95fab368e45eced, 0x11dbcb0218ebb414,
|
||||
0xd652bdc29f26a119, 0x4be76d3346f0495f,
|
||||
0x6f70a4400c562ddb, 0xcb4ccd500f6bb952,
|
||||
0x7e2000a41346a7a7, 0x8ed400668c0c28c8,
|
||||
0x728900802f0f32fa, 0x4f2b40a03ad2ffb9,
|
||||
0xe2f610c84987bfa8, 0xdd9ca7d2df4d7c9,
|
||||
0x91503d1c79720dbb, 0x75a44c6397ce912a,
|
||||
0xc986afbe3ee11aba, 0xfbe85badce996168,
|
||||
0xfae27299423fb9c3, 0xdccd879fc967d41a,
|
||||
0x5400e987bbc1c920, 0x290123e9aab23b68,
|
||||
0xf9a0b6720aaf6521, 0xf808e40e8d5b3e69,
|
||||
0xb60b1d1230b20e04, 0xb1c6f22b5e6f48c2,
|
||||
0x1e38aeb6360b1af3, 0x25c6da63c38de1b0,
|
||||
0x579c487e5a38ad0e, 0x2d835a9df0c6d851,
|
||||
0xf8e431456cf88e65, 0x1b8e9ecb641b58ff,
|
||||
0xe272467e3d222f3f, 0x5b0ed81dcc6abb0f,
|
||||
0x98e947129fc2b4e9, 0x3f2398d747b36224,
|
||||
0x8eec7f0d19a03aad, 0x1953cf68300424ac,
|
||||
0x5fa8c3423c052dd7, 0x3792f412cb06794d,
|
||||
0xe2bbd88bbee40bd0, 0x5b6aceaeae9d0ec4,
|
||||
0xf245825a5a445275, 0xeed6e2f0f0d56712,
|
||||
0x55464dd69685606b, 0xaa97e14c3c26b886,
|
||||
0xd53dd99f4b3066a8, 0xe546a8038efe4029,
|
||||
0xde98520472bdd033, 0x963e66858f6d4440,
|
||||
0xdde7001379a44aa8, 0x5560c018580d5d52,
|
||||
0xaab8f01e6e10b4a6, 0xcab3961304ca70e8,
|
||||
0x3d607b97c5fd0d22, 0x8cb89a7db77c506a,
|
||||
0x77f3608e92adb242, 0x55f038b237591ed3,
|
||||
0x6b6c46dec52f6688, 0x2323ac4b3b3da015,
|
||||
0xabec975e0a0d081a, 0x96e7bd358c904a21,
|
||||
0x7e50d64177da2e54, 0xdde50bd1d5d0b9e9,
|
||||
0x955e4ec64b44e864, 0xbd5af13bef0b113e,
|
||||
0xecb1ad8aeacdd58e, 0x67de18eda5814af2,
|
||||
0x80eacf948770ced7, 0xa1258379a94d028d,
|
||||
0x96ee45813a04330, 0x8bca9d6e188853fc,
|
||||
0x775ea264cf55347d, 0x95364afe032a819d,
|
||||
0x3a83ddbd83f52204, 0xc4926a9672793542,
|
||||
0x75b7053c0f178293, 0x5324c68b12dd6338,
|
||||
0xd3f6fc16ebca5e03, 0x88f4bb1ca6bcf584,
|
||||
0x2b31e9e3d06c32e5, 0x3aff322e62439fcf,
|
||||
0x9befeb9fad487c2, 0x4c2ebe687989a9b3,
|
||||
0xf9d37014bf60a10, 0x538484c19ef38c94,
|
||||
0x2865a5f206b06fb9, 0xf93f87b7442e45d3,
|
||||
0xf78f69a51539d748, 0xb573440e5a884d1b,
|
||||
0x31680a88f8953030, 0xfdc20d2b36ba7c3d,
|
||||
0x3d32907604691b4c, 0xa63f9a49c2c1b10f,
|
||||
0xfcf80dc33721d53, 0xd3c36113404ea4a8,
|
||||
0x645a1cac083126e9, 0x3d70a3d70a3d70a3,
|
||||
0xcccccccccccccccc, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x4000000000000000,
|
||||
0x5000000000000000, 0xa400000000000000,
|
||||
0x4d00000000000000, 0xf020000000000000,
|
||||
0x6c28000000000000, 0xc732000000000000,
|
||||
0x3c7f400000000000, 0x4b9f100000000000,
|
||||
0x1e86d40000000000, 0x1314448000000000,
|
||||
0x17d955a000000000, 0x5dcfab0800000000,
|
||||
0x5aa1cae500000000, 0xf14a3d9e40000000,
|
||||
0x6d9ccd05d0000000, 0xe4820023a2000000,
|
||||
0xdda2802c8a800000, 0xd50b2037ad200000,
|
||||
0x4526f422cc340000, 0x9670b12b7f410000,
|
||||
0x3c0cdd765f114000, 0xa5880a69fb6ac800,
|
||||
0x8eea0d047a457a00, 0x72a4904598d6d880,
|
||||
0x47a6da2b7f864750, 0x999090b65f67d924,
|
||||
0xfff4b4e3f741cf6d, 0xbff8f10e7a8921a4,
|
||||
0xaff72d52192b6a0d, 0x9bf4f8a69f764490,
|
||||
0x2f236d04753d5b4, 0x1d762422c946590,
|
||||
0x424d3ad2b7b97ef5, 0xd2e0898765a7deb2,
|
||||
0x63cc55f49f88eb2f, 0x3cbf6b71c76b25fb,
|
||||
0x8bef464e3945ef7a, 0x97758bf0e3cbb5ac,
|
||||
0x3d52eeed1cbea317, 0x4ca7aaa863ee4bdd,
|
||||
0x8fe8caa93e74ef6a, 0xb3e2fd538e122b44,
|
||||
0x60dbbca87196b616, 0xbc8955e946fe31cd,
|
||||
0x6babab6398bdbe41, 0xc696963c7eed2dd1,
|
||||
0xfc1e1de5cf543ca2, 0x3b25a55f43294bcb,
|
||||
0x49ef0eb713f39ebe, 0x6e3569326c784337,
|
||||
0x49c2c37f07965404, 0xdc33745ec97be906,
|
||||
0x69a028bb3ded71a3, 0xc40832ea0d68ce0c,
|
||||
0xf50a3fa490c30190, 0x792667c6da79e0fa,
|
||||
0x577001b891185938, 0xed4c0226b55e6f86,
|
||||
0x544f8158315b05b4, 0x696361ae3db1c721,
|
||||
0x3bc3a19cd1e38e9, 0x4ab48a04065c723,
|
||||
0x62eb0d64283f9c76, 0x3ba5d0bd324f8394,
|
||||
0xca8f44ec7ee36479, 0x7e998b13cf4e1ecb,
|
||||
0x9e3fedd8c321a67e, 0xc5cfe94ef3ea101e,
|
||||
0xbba1f1d158724a12, 0x2a8a6e45ae8edc97,
|
||||
0xf52d09d71a3293bd, 0x593c2626705f9c56,
|
||||
0x6f8b2fb00c77836c, 0xb6dfb9c0f956447,
|
||||
0x4724bd4189bd5eac, 0x58edec91ec2cb657,
|
||||
0x2f2967b66737e3ed, 0xbd79e0d20082ee74,
|
||||
0xecd8590680a3aa11, 0xe80e6f4820cc9495,
|
||||
0x3109058d147fdcdd, 0xbd4b46f0599fd415,
|
||||
0x6c9e18ac7007c91a, 0x3e2cf6bc604ddb0,
|
||||
0x84db8346b786151c, 0xe612641865679a63,
|
||||
0x4fcb7e8f3f60c07e, 0xe3be5e330f38f09d,
|
||||
0x5cadf5bfd3072cc5, 0x73d9732fc7c8f7f6,
|
||||
0x2867e7fddcdd9afa, 0xb281e1fd541501b8,
|
||||
0x1f225a7ca91a4226, 0x3375788de9b06958,
|
||||
0x52d6b1641c83ae, 0xc0678c5dbd23a49a,
|
||||
0xf840b7ba963646e0, 0xb650e5a93bc3d898,
|
||||
0xa3e51f138ab4cebe, 0xc66f336c36b10137,
|
||||
0xb80b0047445d4184, 0xa60dc059157491e5,
|
||||
0x87c89837ad68db2f, 0x29babe4598c311fb,
|
||||
0xf4296dd6fef3d67a, 0x1899e4a65f58660c,
|
||||
0x5ec05dcff72e7f8f, 0x76707543f4fa1f73,
|
||||
0x6a06494a791c53a8, 0x487db9d17636892,
|
||||
0x45a9d2845d3c42b6, 0xb8a2392ba45a9b2,
|
||||
0x8e6cac7768d7141e, 0x3207d795430cd926,
|
||||
0x7f44e6bd49e807b8, 0x5f16206c9c6209a6,
|
||||
0x36dba887c37a8c0f, 0xc2494954da2c9789,
|
||||
0xf2db9baa10b7bd6c, 0x6f92829494e5acc7,
|
||||
0xcb772339ba1f17f9, 0xff2a760414536efb,
|
||||
0xfef5138519684aba, 0x7eb258665fc25d69,
|
||||
0xef2f773ffbd97a61, 0xaafb550ffacfd8fa,
|
||||
0x95ba2a53f983cf38, 0xdd945a747bf26183,
|
||||
0x94f971119aeef9e4, 0x7a37cd5601aab85d,
|
||||
0xac62e055c10ab33a, 0x577b986b314d6009,
|
||||
0xed5a7e85fda0b80b, 0x14588f13be847307,
|
||||
0x596eb2d8ae258fc8, 0x6fca5f8ed9aef3bb,
|
||||
0x25de7bb9480d5854, 0xaf561aa79a10ae6a,
|
||||
0x1b2ba1518094da04, 0x90fb44d2f05d0842,
|
||||
0x353a1607ac744a53, 0x42889b8997915ce8,
|
||||
0x69956135febada11, 0x43fab9837e699095,
|
||||
0x94f967e45e03f4bb, 0x1d1be0eebac278f5,
|
||||
0x6462d92a69731732, 0x7d7b8f7503cfdcfe,
|
||||
0x5cda735244c3d43e, 0x3a0888136afa64a7,
|
||||
0x88aaa1845b8fdd0, 0x8aad549e57273d45,
|
||||
0x36ac54e2f678864b, 0x84576a1bb416a7dd,
|
||||
0x656d44a2a11c51d5, 0x9f644ae5a4b1b325,
|
||||
0x873d5d9f0dde1fee, 0xa90cb506d155a7ea,
|
||||
0x9a7f12442d588f2, 0xc11ed6d538aeb2f,
|
||||
0x8f1668c8a86da5fa, 0xf96e017d694487bc,
|
||||
0x37c981dcc395a9ac, 0x85bbe253f47b1417,
|
||||
0x93956d7478ccec8e, 0x387ac8d1970027b2,
|
||||
0x6997b05fcc0319e, 0x441fece3bdf81f03,
|
||||
0xd527e81cad7626c3, 0x8a71e223d8d3b074,
|
||||
0xf6872d5667844e49, 0xb428f8ac016561db,
|
||||
0xe13336d701beba52, 0xecc0024661173473,
|
||||
0x27f002d7f95d0190, 0x31ec038df7b441f4,
|
||||
0x7e67047175a15271, 0xf0062c6e984d386,
|
||||
0x52c07b78a3e60868, 0xa7709a56ccdf8a82,
|
||||
0x88a66076400bb691, 0x6acff893d00ea435,
|
||||
0x583f6b8c4124d43, 0xc3727a337a8b704a,
|
||||
0x744f18c0592e4c5c, 0x1162def06f79df73,
|
||||
0x8addcb5645ac2ba8, 0x6d953e2bd7173692,
|
||||
0xc8fa8db6ccdd0437, 0x1d9c9892400a22a2,
|
||||
0x2503beb6d00cab4b, 0x2e44ae64840fd61d,
|
||||
0x5ceaecfed289e5d2, 0x7425a83e872c5f47,
|
||||
0xd12f124e28f77719, 0x82bd6b70d99aaa6f,
|
||||
0x636cc64d1001550b, 0x3c47f7e05401aa4e,
|
||||
0x65acfaec34810a71, 0x7f1839a741a14d0d,
|
||||
0x1ede48111209a050, 0x934aed0aab460432,
|
||||
0xf81da84d5617853f, 0x36251260ab9d668e,
|
||||
0xc1d72b7c6b426019, 0xb24cf65b8612f81f,
|
||||
0xdee033f26797b627, 0x169840ef017da3b1,
|
||||
0x8e1f289560ee864e, 0xf1a6f2bab92a27e2,
|
||||
0xae10af696774b1db, 0xacca6da1e0a8ef29,
|
||||
0x17fd090a58d32af3, 0xddfc4b4cef07f5b0,
|
||||
0x4abdaf101564f98e, 0x9d6d1ad41abe37f1,
|
||||
0x84c86189216dc5ed, 0x32fd3cf5b4e49bb4,
|
||||
0x3fbc8c33221dc2a1, 0xfabaf3feaa5334a,
|
||||
0x29cb4d87f2a7400e, 0x743e20e9ef511012,
|
||||
0x914da9246b255416, 0x1ad089b6c2f7548e,
|
||||
0xa184ac2473b529b1, 0xc9e5d72d90a2741e,
|
||||
0x7e2fa67c7a658892, 0xddbb901b98feeab7,
|
||||
0x552a74227f3ea565, 0xd53a88958f87275f,
|
||||
0x8a892abaf368f137, 0x2d2b7569b0432d85,
|
||||
0x9c3b29620e29fc73, 0x8349f3ba91b47b8f,
|
||||
0x241c70a936219a73, 0xed238cd383aa0110,
|
||||
0xf4363804324a40aa, 0xb143c6053edcd0d5,
|
||||
0xdd94b7868e94050a, 0xca7cf2b4191c8326,
|
||||
0xfd1c2f611f63a3f0, 0xbc633b39673c8cec,
|
||||
0xd5be0503e085d813, 0x4b2d8644d8a74e18,
|
||||
0xddf8e7d60ed1219e, 0xcabb90e5c942b503,
|
||||
0x3d6a751f3b936243, 0xcc512670a783ad4,
|
||||
0x27fb2b80668b24c5, 0xb1f9f660802dedf6,
|
||||
0x5e7873f8a0396973, 0xdb0b487b6423e1e8,
|
||||
0x91ce1a9a3d2cda62, 0x7641a140cc7810fb,
|
||||
0xa9e904c87fcb0a9d, 0x546345fa9fbdcd44,
|
||||
0xa97c177947ad4095, 0x49ed8eabcccc485d,
|
||||
0x5c68f256bfff5a74, 0x73832eec6fff3111,
|
||||
0xc831fd53c5ff7eab, 0xba3e7ca8b77f5e55,
|
||||
0x28ce1bd2e55f35eb, 0x7980d163cf5b81b3,
|
||||
0xd7e105bcc332621f, 0x8dd9472bf3fefaa7,
|
||||
0xb14f98f6f0feb951, 0x6ed1bf9a569f33d3,
|
||||
0xa862f80ec4700c8, 0xcd27bb612758c0fa,
|
||||
0x8038d51cb897789c, 0xe0470a63e6bd56c3,
|
||||
0x1858ccfce06cac74, 0xf37801e0c43ebc8,
|
||||
0xd30560258f54e6ba, 0x47c6b82ef32a2069,
|
||||
0x4cdc331d57fa5441, 0xe0133fe4adf8e952,
|
||||
0x58180fddd97723a6, 0x570f09eaa7ea7648
|
||||
};
|
||||
|
||||
}}}}} // Namespaces
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_SIGNIFICAND_TABLES_HPP
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2022 Peter Dimov
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_FROM_CHARS_HPP_INCLUDED
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_FROM_CHARS_HPP_INCLUDED
|
||||
|
||||
#include <boost/json/detail/charconv/detail/config.hpp>
|
||||
#include <boost/json/detail/charconv/detail/from_chars_result.hpp>
|
||||
#include <boost/json/detail/charconv/chars_format.hpp>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Floating Point
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
std::errc errno_to_errc(int errno_value) noexcept;
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
BOOST_JSON_DECL from_chars_result from_chars(const char* first, const char* last, double& value, chars_format fmt = chars_format::general) noexcept;
|
||||
|
||||
} // namespace charconv
|
||||
} // namespace detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_JSON_DETAIL_CHARCONV_FROM_CHARS_HPP_INCLUDED
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Copyright 2022 Peter Dimov
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// https://stackoverflow.com/questions/38060411/visual-studio-2015-wont-suppress-error-c4996
|
||||
#ifndef _SCL_SECURE_NO_WARNINGS
|
||||
# define _SCL_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#ifndef NO_WARN_MBCS_MFC_DEPRECATION
|
||||
# define NO_WARN_MBCS_MFC_DEPRECATION
|
||||
#endif
|
||||
|
||||
#include <boost/json/detail/charconv/detail/fast_float/fast_float.hpp>
|
||||
#include <boost/json/detail/charconv/detail/from_chars_float_impl.hpp>
|
||||
#include <boost/json/detail/charconv/from_chars.hpp>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 5
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
std::errc boost::json::detail::charconv::detail::errno_to_errc(int errno_value) noexcept
|
||||
{
|
||||
switch (errno_value)
|
||||
{
|
||||
case EINVAL:
|
||||
return std::errc::invalid_argument;
|
||||
case ERANGE:
|
||||
return std::errc::result_out_of_range;
|
||||
default:
|
||||
return std::errc();
|
||||
}
|
||||
}
|
||||
|
||||
boost::json::detail::charconv::from_chars_result boost::json::detail::charconv::from_chars(const char* first, const char* last, double& value, boost::json::detail::charconv::chars_format fmt) noexcept
|
||||
{
|
||||
if (fmt != boost::json::detail::charconv::chars_format::hex)
|
||||
{
|
||||
return boost::json::detail::charconv::detail::fast_float::from_chars(first, last, value, fmt);
|
||||
}
|
||||
return boost::json::detail::charconv::detail::from_chars_float_impl(first, last, value, fmt);
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// Copyright 2023 Matt Borland
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CHARCONV_LIMITS_HPP
|
||||
#define BOOST_JSON_DETAIL_CHARCONV_LIMITS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace json { namespace detail { namespace charconv {
|
||||
|
||||
// limits<T>::max_chars10: the minimum size of the buffer that needs to be
|
||||
// passed to to_chars to guarantee successful conversion for all values of
|
||||
// type T, when either no base is passed, or base 10 is passed
|
||||
//
|
||||
// limits<T>::max_chars: the minimum size of the buffer that needs to be
|
||||
// passed to to_chars to guarantee successful conversion for all values of
|
||||
// type T, for any value of base
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
constexpr int exp_digits( int exp )
|
||||
{
|
||||
return exp < 100? 2: exp < 1000? 3: exp < 10000? 4: 5;
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
|
||||
template<class T> struct is_int128: std::is_same<T, boost::int128_type> {};
|
||||
template<class T> struct is_uint128: std::is_same<T, boost::int128_type> {};
|
||||
|
||||
#else
|
||||
|
||||
template<class T> struct is_int128: std::false_type {};
|
||||
template<class T> struct is_uint128: std::false_type {};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T> struct limits
|
||||
{
|
||||
static constexpr int max_chars10 =
|
||||
|
||||
// int128_t
|
||||
detail::is_int128<T>::value? 38+2: // digits10 + 1 + sign
|
||||
|
||||
// uint128_t
|
||||
detail::is_uint128<T>::value? 38+1: // digits10 + 1
|
||||
|
||||
// integral
|
||||
std::numeric_limits<T>::is_integer? std::numeric_limits<T>::digits10 + 1 + std::numeric_limits<T>::is_signed:
|
||||
|
||||
// floating point
|
||||
std::numeric_limits<T>::max_digits10 + 3 + 2 + detail::exp_digits( std::numeric_limits<T>::max_exponent10 ); // -1.(max_digits10)e+(max_exp)
|
||||
|
||||
static constexpr int max_chars =
|
||||
|
||||
// int128_t
|
||||
detail::is_int128<T>::value? 127+2: // digits + 1 + sign
|
||||
|
||||
// uint128_t
|
||||
detail::is_uint128<T>::value? 128+1: // digits + 1
|
||||
|
||||
// integral
|
||||
std::numeric_limits<T>::is_integer? std::numeric_limits<T>::digits + 1 + std::numeric_limits<T>::is_signed:
|
||||
|
||||
// floating point
|
||||
std::numeric_limits<T>::max_digits10 + 3 + 2 + detail::exp_digits( std::numeric_limits<T>::max_exponent10 ); // as above
|
||||
};
|
||||
|
||||
#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
|
||||
|
||||
// Definitions of in-class constexpr members are allowed but deprecated in C++17
|
||||
|
||||
template<typename T> constexpr int limits<T>::max_chars10;
|
||||
template<typename T> constexpr int limits<T>::max_chars;
|
||||
|
||||
#endif // defined(BOOST_NO_CXX17_INLINE_VARIABLES)
|
||||
|
||||
}}}} // namespace boost::charconv
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_CHARCONV_LIMITS_HPP
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_CONFIG_HPP
|
||||
#define BOOST_JSON_DETAIL_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
// detect 32/64 bit
|
||||
#if UINTPTR_MAX == UINT64_MAX
|
||||
# define BOOST_JSON_ARCH 64
|
||||
#elif UINTPTR_MAX == UINT32_MAX
|
||||
# define BOOST_JSON_ARCH 32
|
||||
#else
|
||||
# error Unknown or unsupported architecture, please open an issue
|
||||
#endif
|
||||
|
||||
// VFALCO Copied from Boost.Config
|
||||
// This is a derivative work.
|
||||
#ifndef BOOST_JSON_NODISCARD
|
||||
# ifdef __has_cpp_attribute
|
||||
// clang-6 accepts [[nodiscard]] with -std=c++14, but warns about it -pedantic
|
||||
# if __has_cpp_attribute(nodiscard) && !(defined(__clang__) && (__cplusplus < 201703L))
|
||||
# define BOOST_JSON_NODISCARD [[nodiscard]]
|
||||
# else
|
||||
# define BOOST_JSON_NODISCARD
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_JSON_NODISCARD
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_JSON_REQUIRE_CONST_INIT
|
||||
# define BOOST_JSON_REQUIRE_CONST_INIT
|
||||
# if __cpp_constinit >= 201907L
|
||||
# undef BOOST_JSON_REQUIRE_CONST_INIT
|
||||
# define BOOST_JSON_REQUIRE_CONST_INIT constinit
|
||||
# elif defined(__clang__) && defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(clang::require_constant_initialization)
|
||||
# undef BOOST_JSON_REQUIRE_CONST_INIT
|
||||
# define BOOST_JSON_REQUIRE_CONST_INIT [[clang::require_constant_initialization]]
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_JSON_NO_DESTROY
|
||||
# if defined(__clang__) && defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(clang::no_destroy)
|
||||
# define BOOST_JSON_NO_DESTROY [[clang::no_destroy]]
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// BOOST_NORETURN ---------------------------------------------//
|
||||
// Macro to use before a function declaration/definition to designate
|
||||
// the function as not returning normally (i.e. with a return statement
|
||||
// or by leaving the function scope, if the function return type is void).
|
||||
#if !defined(BOOST_NORETURN)
|
||||
# if defined(_MSC_VER)
|
||||
# define BOOST_NORETURN __declspec(noreturn)
|
||||
# elif defined(__GNUC__)
|
||||
# define BOOST_NORETURN __attribute__ ((__noreturn__))
|
||||
# elif defined(__has_attribute) && defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x5130)
|
||||
# if __has_attribute(noreturn)
|
||||
# define BOOST_NORETURN [[noreturn]]
|
||||
# endif
|
||||
# elif defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(noreturn)
|
||||
# define BOOST_NORETURN [[noreturn]]
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_ASSERT
|
||||
#define BOOST_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_STATIC_ASSERT
|
||||
#define BOOST_STATIC_ASSERT( ... ) static_assert(__VA_ARGS__, #__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_FALLTHROUGH
|
||||
#define BOOST_FALLTHROUGH [[fallthrough]]
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_FORCEINLINE
|
||||
# ifdef _MSC_VER
|
||||
# define BOOST_FORCEINLINE __forceinline
|
||||
# elif defined(__GNUC__) || defined(__clang__)
|
||||
# define BOOST_FORCEINLINE inline __attribute__((always_inline))
|
||||
# else
|
||||
# define BOOST_FORCEINLINE inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NOINLINE
|
||||
# ifdef _MSC_VER
|
||||
# define BOOST_NOINLINE __declspec(noinline)
|
||||
# elif defined(__GNUC__) || defined(__clang__)
|
||||
# define BOOST_NOINLINE __attribute__((noinline))
|
||||
# else
|
||||
# define BOOST_NOINLINE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_THROW_EXCEPTION
|
||||
# ifndef BOOST_NO_EXCEPTIONS
|
||||
# define BOOST_THROW_EXCEPTION(x) throw(x)
|
||||
# else
|
||||
# define BOOST_THROW_EXCEPTION(x) do{}while(0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ! defined(BOOST_JSON_NO_SSE2) && \
|
||||
! defined(BOOST_JSON_USE_SSE2)
|
||||
# if (defined(_M_IX86) && _M_IX86_FP == 2) || \
|
||||
defined(_M_X64) || defined(__SSE2__)
|
||||
# define BOOST_JSON_USE_SSE2
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_SYMBOL_VISIBLE
|
||||
#define BOOST_SYMBOL_VISIBLE
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_JSON_DOCS)
|
||||
# define BOOST_JSON_DECL
|
||||
#else
|
||||
# if (defined(BOOST_JSON_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_JSON_STATIC_LINK)
|
||||
# if defined(BOOST_JSON_SOURCE)
|
||||
# define BOOST_JSON_DECL BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_JSON_DECL BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
# endif // shared lib
|
||||
# ifndef BOOST_JSON_DECL
|
||||
# define BOOST_JSON_DECL
|
||||
# endif
|
||||
# if !defined(BOOST_JSON_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_JSON_NO_LIB)
|
||||
# define BOOST_LIB_NAME boost_json
|
||||
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_JSON_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
# endif
|
||||
# include <boost/config/auto_link.hpp>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_JSON_LIKELY
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define BOOST_JSON_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# else
|
||||
# define BOOST_JSON_LIKELY(x) x
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_JSON_UNLIKELY
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define BOOST_JSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# else
|
||||
# define BOOST_JSON_UNLIKELY(x) x
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_JSON_UNREACHABLE
|
||||
# ifdef _MSC_VER
|
||||
# define BOOST_JSON_UNREACHABLE() __assume(0)
|
||||
# elif defined(__GNUC__) || defined(__clang__)
|
||||
# define BOOST_JSON_UNREACHABLE() __builtin_unreachable()
|
||||
# elif defined(__has_builtin)
|
||||
# if __has_builtin(__builtin_unreachable)
|
||||
# define BOOST_JSON_UNREACHABLE() __builtin_unreachable()
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_JSON_UNREACHABLE() static_cast<void>(0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_JSON_ASSUME
|
||||
# define BOOST_JSON_ASSUME(x) (!!(x) ? void() : BOOST_JSON_UNREACHABLE())
|
||||
# ifdef _MSC_VER
|
||||
# undef BOOST_JSON_ASSUME
|
||||
# define BOOST_JSON_ASSUME(x) __assume(!!(x))
|
||||
# elif defined(__has_builtin)
|
||||
# if __has_builtin(__builtin_assume)
|
||||
# undef BOOST_JSON_ASSUME
|
||||
# define BOOST_JSON_ASSUME(x) __builtin_assume(!!(x))
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// older versions of msvc and clang don't always
|
||||
// constant initialize when they are supposed to
|
||||
#ifndef BOOST_JSON_WEAK_CONSTINIT
|
||||
# if defined(_MSC_VER) && ! defined(__clang__) && _MSC_VER < 1920
|
||||
# define BOOST_JSON_WEAK_CONSTINIT
|
||||
# elif defined(__clang__) && __clang_major__ < 4
|
||||
# define BOOST_JSON_WEAK_CONSTINIT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// These macros are private, for tests, do not change
|
||||
// them or else previously built libraries won't match.
|
||||
#ifndef BOOST_JSON_MAX_STRING_SIZE
|
||||
# define BOOST_JSON_NO_MAX_STRING_SIZE
|
||||
# define BOOST_JSON_MAX_STRING_SIZE 0x7ffffffe
|
||||
#endif
|
||||
#ifndef BOOST_JSON_MAX_STRUCTURED_SIZE
|
||||
# define BOOST_JSON_NO_MAX_STRUCTURED_SIZE
|
||||
# define BOOST_JSON_MAX_STRUCTURED_SIZE 0x7ffffffe
|
||||
#endif
|
||||
#ifndef BOOST_JSON_STACK_BUFFER_SIZE
|
||||
# define BOOST_JSON_NO_STACK_BUFFER_SIZE
|
||||
# if defined(__i386__) || defined(__x86_64__) || \
|
||||
defined(_M_IX86) || defined(_M_X64)
|
||||
# define BOOST_JSON_STACK_BUFFER_SIZE 4096
|
||||
# else
|
||||
// If we are not on Intel, then assume we are on
|
||||
// embedded and use a smaller stack size. If this
|
||||
// is not suitable, the user can define the macro
|
||||
// themselves when building the library or including
|
||||
// src.hpp.
|
||||
# define BOOST_JSON_STACK_BUFFER_SIZE 256
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if ! defined(BOOST_JSON_BIG_ENDIAN) && ! defined(BOOST_JSON_LITTLE_ENDIAN)
|
||||
// Copied from Boost.Endian
|
||||
# if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define BOOST_JSON_LITTLE_ENDIAN
|
||||
# elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define BOOST_JSON_BIG_ENDIAN
|
||||
# elif defined(__LITTLE_ENDIAN__)
|
||||
# define BOOST_JSON_LITTLE_ENDIAN
|
||||
# elif defined(__BIG_ENDIAN__)
|
||||
# define BOOST_JSON_BIG_ENDIAN
|
||||
# elif defined(_MSC_VER) || defined(__i386__) || defined(__x86_64__)
|
||||
# define BOOST_JSON_LITTLE_ENDIAN
|
||||
# else
|
||||
# error The Boost.JSON library could not determine the endianness of this platform. Define either BOOST_JSON_BIG_ENDIAN or BOOST_JSON_LITTLE_ENDIAN.
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_constinit) && __cpp_constinit >= 201907L
|
||||
# define BOOST_JSON_CONSTINIT constinit
|
||||
#elif defined(__has_cpp_attribute) && defined(__clang__)
|
||||
# if __has_cpp_attribute(clang::require_constant_initialization)
|
||||
# define BOOST_JSON_CONSTINIT [[clang::require_constant_initialization]]
|
||||
# endif
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 10)
|
||||
# define BOOST_JSON_CONSTINIT __constinit
|
||||
#endif
|
||||
#ifndef BOOST_JSON_CONSTINIT
|
||||
# define BOOST_JSON_CONSTINIT
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
template<class...>
|
||||
struct make_void
|
||||
{
|
||||
using type =void;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
using void_t = typename
|
||||
make_void<Ts...>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_cvref = typename
|
||||
std::remove_cv<typename
|
||||
std::remove_reference<T>::type>::type;
|
||||
|
||||
template<class T, class U>
|
||||
T exchange(T& t, U u) noexcept
|
||||
{
|
||||
T v = std::move(t);
|
||||
t = std::move(u);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* This is a derivative work, original copyright:
|
||||
|
||||
Copyright Eric Niebler 2013-present
|
||||
|
||||
Use, modification and distribution is subject to 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)
|
||||
|
||||
Project home: https://github.com/ericniebler/range-v3
|
||||
*/
|
||||
template<typename T>
|
||||
struct static_const
|
||||
{
|
||||
static constexpr T value {};
|
||||
};
|
||||
template<typename T>
|
||||
constexpr T static_const<T>::value;
|
||||
|
||||
#define BOOST_JSON_INLINE_VARIABLE(name, type) \
|
||||
namespace { constexpr auto& name = \
|
||||
::boost::json::detail::static_const<type>::value; \
|
||||
} struct _unused_ ## name ## _semicolon_bait_
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DEFAULT_RESOURCE_HPP
|
||||
#define BOOST_JSON_DEFAULT_RESOURCE_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <new>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4251) // class needs to have dll-interface to be used by clients of class
|
||||
#pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class
|
||||
#endif
|
||||
|
||||
// A simple memory resource that uses operator new and delete.
|
||||
class
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_JSON_DECL
|
||||
default_resource final
|
||||
: public memory_resource
|
||||
{
|
||||
union holder;
|
||||
|
||||
#ifndef BOOST_JSON_WEAK_CONSTINIT
|
||||
# ifndef BOOST_JSON_NO_DESTROY
|
||||
static holder instance_;
|
||||
# else
|
||||
BOOST_JSON_NO_DESTROY
|
||||
static default_resource instance_;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
static
|
||||
memory_resource*
|
||||
get() noexcept
|
||||
{
|
||||
#ifdef BOOST_JSON_WEAK_CONSTINIT
|
||||
static default_resource instance_;
|
||||
#endif
|
||||
return reinterpret_cast<memory_resource*>(
|
||||
reinterpret_cast<std::uintptr_t*>(
|
||||
&instance_));
|
||||
}
|
||||
|
||||
~default_resource();
|
||||
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t) override;
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t,
|
||||
std::size_t) override;
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept override;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
union default_resource::
|
||||
holder
|
||||
{
|
||||
#ifndef BOOST_JSON_WEAK_CONSTINIT
|
||||
constexpr
|
||||
#endif
|
||||
holder()
|
||||
: mr()
|
||||
{
|
||||
}
|
||||
|
||||
~holder()
|
||||
{
|
||||
}
|
||||
|
||||
default_resource mr;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_DIGEST_HPP
|
||||
#define BOOST_JSON_DETAIL_DIGEST_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
// Calculate salted digest of string
|
||||
template<class ForwardIterator>
|
||||
std::size_t
|
||||
digest(
|
||||
ForwardIterator b,
|
||||
ForwardIterator e,
|
||||
std::size_t salt) noexcept
|
||||
{
|
||||
#if BOOST_JSON_ARCH == 64
|
||||
std::uint64_t const prime = 0x100000001B3ULL;
|
||||
std::uint64_t hash = 0xcbf29ce484222325ULL;
|
||||
#else
|
||||
std::uint32_t const prime = 0x01000193UL;
|
||||
std::uint32_t hash = 0x811C9DC5UL;
|
||||
#endif
|
||||
hash += salt;
|
||||
for(; b != e; ++b)
|
||||
hash = (*b ^ hash) * prime;
|
||||
return hash;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_EXCEPT_HPP
|
||||
#define BOOST_JSON_DETAIL_EXCEPT_HPP
|
||||
|
||||
#include <boost/json/error.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
#define BOOST_JSON_FAIL(ec, e) \
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; \
|
||||
(ec).assign(e, &loc);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
BOOST_NORETURN
|
||||
throw_system_error(
|
||||
error_code const& ec,
|
||||
source_location const& loc = BOOST_CURRENT_LOCATION);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
BOOST_NORETURN
|
||||
throw_system_error(
|
||||
error e,
|
||||
source_location const* loc);
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_FORMAT_HPP
|
||||
#define BOOST_JSON_DETAIL_FORMAT_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
int constexpr max_number_chars =
|
||||
1 + // '-'
|
||||
19 + // unsigned 64-bit mantissa
|
||||
1 + // 'e'
|
||||
1 + // '-'
|
||||
5; // unsigned 16-bit exponent
|
||||
|
||||
BOOST_JSON_DECL
|
||||
unsigned
|
||||
format_uint64(
|
||||
char* dest,
|
||||
std::uint64_t value) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
unsigned
|
||||
format_int64(
|
||||
char* dest, int64_t i) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
unsigned
|
||||
format_double(
|
||||
char* dest, double d, bool allow_infinity_and_nan = false) noexcept;
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_HANDLER_HPP
|
||||
#define BOOST_JSON_DETAIL_HANDLER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/string_view.hpp>
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/string.hpp>
|
||||
#include <boost/json/value_stack.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
struct handler
|
||||
{
|
||||
static constexpr std::size_t
|
||||
max_object_size = object::max_size();
|
||||
|
||||
static constexpr std::size_t
|
||||
max_array_size = array::max_size();
|
||||
|
||||
static constexpr std::size_t
|
||||
max_key_size = string::max_size();
|
||||
|
||||
static constexpr std::size_t
|
||||
max_string_size = string::max_size();
|
||||
|
||||
value_stack st;
|
||||
|
||||
template<class... Args>
|
||||
explicit
|
||||
handler(Args&&... args);
|
||||
|
||||
inline bool on_document_begin(error_code& ec);
|
||||
inline bool on_document_end(error_code& ec);
|
||||
inline bool on_object_begin(error_code& ec);
|
||||
inline bool on_object_end(std::size_t n, error_code& ec);
|
||||
inline bool on_array_begin(error_code& ec);
|
||||
inline bool on_array_end(std::size_t n, error_code& ec);
|
||||
inline bool on_key_part(string_view s, std::size_t n, error_code& ec);
|
||||
inline bool on_key(string_view s, std::size_t n, error_code& ec);
|
||||
inline bool on_string_part(string_view s, std::size_t n, error_code& ec);
|
||||
inline bool on_string(string_view s, std::size_t n, error_code& ec);
|
||||
inline bool on_number_part(string_view, error_code&);
|
||||
inline bool on_int64(std::int64_t i, string_view, error_code& ec);
|
||||
inline bool on_uint64(std::uint64_t u, string_view, error_code& ec);
|
||||
inline bool on_double(double d, string_view, error_code& ec);
|
||||
inline bool on_bool(bool b, error_code& ec);
|
||||
inline bool on_null(error_code& ec);
|
||||
inline bool on_comment_part(string_view, error_code&);
|
||||
inline bool on_comment(string_view, error_code&);
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_ARRAY_HPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_ARRAY_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
unchecked_array::
|
||||
~unchecked_array()
|
||||
{
|
||||
if(! data_ ||
|
||||
sp_.is_not_shared_and_deallocate_is_trivial())
|
||||
return;
|
||||
for(unsigned long i = 0;
|
||||
i < size_; ++i)
|
||||
data_[i].~value();
|
||||
}
|
||||
|
||||
void
|
||||
unchecked_array::
|
||||
relocate(value* dest) noexcept
|
||||
{
|
||||
if(size_ > 0)
|
||||
std::memcpy(
|
||||
static_cast<void*>(dest),
|
||||
data_, size_ * sizeof(value));
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_DEFAULT_RESOURCE_IPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_DEFAULT_RESOURCE_IPP
|
||||
|
||||
#include <boost/json/detail/default_resource.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
#ifndef BOOST_JSON_WEAK_CONSTINIT
|
||||
# ifndef BOOST_JSON_NO_DESTROY
|
||||
BOOST_JSON_REQUIRE_CONST_INIT
|
||||
default_resource::holder
|
||||
default_resource::instance_;
|
||||
# else
|
||||
BOOST_JSON_REQUIRE_CONST_INIT
|
||||
default_resource
|
||||
default_resource::instance_;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// this is here so that ~memory_resource
|
||||
// is emitted in the library instead of
|
||||
// the user's TU.
|
||||
default_resource::
|
||||
~default_resource() = default;
|
||||
|
||||
void*
|
||||
default_resource::
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t)
|
||||
{
|
||||
return ::operator new(n);
|
||||
}
|
||||
|
||||
void
|
||||
default_resource::
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t,
|
||||
std::size_t)
|
||||
{
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
bool
|
||||
default_resource::
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept
|
||||
{
|
||||
return this == &mr;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_EXCEPT_IPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_EXCEPT_IPP
|
||||
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
|
||||
void
|
||||
throw_system_error(
|
||||
error_code const& ec,
|
||||
source_location const& loc)
|
||||
{
|
||||
throw_exception(
|
||||
system_error(ec),
|
||||
loc);
|
||||
}
|
||||
|
||||
void
|
||||
throw_system_error(
|
||||
error e,
|
||||
source_location const* loc)
|
||||
{
|
||||
error_code ec;
|
||||
ec.assign(e, loc);
|
||||
|
||||
throw_exception(
|
||||
system_error(ec),
|
||||
*loc);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Peter Dimov (pdimov 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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
|
||||
|
||||
#include <boost/json/detail/ryu/ryu.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
/* Reference work:
|
||||
|
||||
https://www.ampl.com/netlib/fp/dtoa.c
|
||||
https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
https://kkimdev.github.io/posts/2018/06/15/IEEE-754-Floating-Point-Type-in-C++.html
|
||||
*/
|
||||
|
||||
inline char const* digits_lut() noexcept
|
||||
{
|
||||
return
|
||||
"00010203040506070809"
|
||||
"10111213141516171819"
|
||||
"20212223242526272829"
|
||||
"30313233343536373839"
|
||||
"40414243444546474849"
|
||||
"50515253545556575859"
|
||||
"60616263646566676869"
|
||||
"70717273747576777879"
|
||||
"80818283848586878889"
|
||||
"90919293949596979899";
|
||||
}
|
||||
|
||||
inline void format_four_digits( char * dest, unsigned v )
|
||||
{
|
||||
std::memcpy( dest + 2, digits_lut() + (v % 100) * 2, 2 );
|
||||
std::memcpy( dest , digits_lut() + (v / 100) * 2, 2 );
|
||||
}
|
||||
|
||||
inline void format_two_digits( char * dest, unsigned v )
|
||||
{
|
||||
std::memcpy( dest, digits_lut() + v * 2, 2 );
|
||||
}
|
||||
|
||||
inline void format_digit( char * dest, unsigned v )
|
||||
{
|
||||
*dest = static_cast<char>( v + '0' );
|
||||
}
|
||||
|
||||
unsigned
|
||||
format_uint64(
|
||||
char* dest,
|
||||
std::uint64_t v) noexcept
|
||||
{
|
||||
if(v < 10)
|
||||
{
|
||||
*dest = static_cast<char>( '0' + v );
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[ 24 ];
|
||||
|
||||
char * p = buffer + 24;
|
||||
|
||||
while( v >= 1000 )
|
||||
{
|
||||
p -= 4;
|
||||
format_four_digits( p, v % 10000 );
|
||||
v /= 10000;
|
||||
}
|
||||
|
||||
if( v >= 10 )
|
||||
{
|
||||
p -= 2;
|
||||
format_two_digits( p, v % 100 );
|
||||
v /= 100;
|
||||
}
|
||||
|
||||
if( v )
|
||||
{
|
||||
p -= 1;
|
||||
format_digit( p, static_cast<unsigned>(v) );
|
||||
}
|
||||
|
||||
unsigned const n = static_cast<unsigned>( buffer + 24 - p );
|
||||
std::memcpy( dest, p, n );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned
|
||||
format_int64(
|
||||
char* dest, int64_t i) noexcept
|
||||
{
|
||||
std::uint64_t ui = static_cast<
|
||||
std::uint64_t>(i);
|
||||
if(i >= 0)
|
||||
return format_uint64(dest, ui);
|
||||
*dest++ = '-';
|
||||
ui = ~ui + 1;
|
||||
return 1 + format_uint64(dest, ui);
|
||||
}
|
||||
|
||||
unsigned
|
||||
format_double(
|
||||
char* dest, double d, bool allow_infinity_and_nan) noexcept
|
||||
{
|
||||
return static_cast<int>(
|
||||
ryu::d2s_buffered_n(d, dest, allow_infinity_and_nan));
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_HANDLER_HPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_HANDLER_HPP
|
||||
|
||||
#include <boost/json/detail/handler.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
template<class... Args>
|
||||
handler::
|
||||
handler(Args&&... args)
|
||||
: st(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_document_begin(
|
||||
error_code&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_document_end(
|
||||
error_code&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_object_begin(
|
||||
error_code&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_object_end(
|
||||
std::size_t n,
|
||||
error_code&)
|
||||
{
|
||||
st.push_object(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_array_begin(
|
||||
error_code&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_array_end(
|
||||
std::size_t n,
|
||||
error_code&)
|
||||
{
|
||||
st.push_array(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_key_part(
|
||||
string_view s,
|
||||
std::size_t,
|
||||
error_code&)
|
||||
{
|
||||
st.push_chars(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_key(
|
||||
string_view s,
|
||||
std::size_t,
|
||||
error_code&)
|
||||
{
|
||||
st.push_key(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_string_part(
|
||||
string_view s,
|
||||
std::size_t,
|
||||
error_code&)
|
||||
{
|
||||
st.push_chars(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_string(
|
||||
string_view s,
|
||||
std::size_t,
|
||||
error_code&)
|
||||
{
|
||||
st.push_string(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_number_part(
|
||||
string_view,
|
||||
error_code&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_int64(
|
||||
std::int64_t i,
|
||||
string_view,
|
||||
error_code&)
|
||||
{
|
||||
st.push_int64(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_uint64(
|
||||
std::uint64_t u,
|
||||
string_view,
|
||||
error_code&)
|
||||
{
|
||||
st.push_uint64(u);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_double(
|
||||
double d,
|
||||
string_view,
|
||||
error_code&)
|
||||
{
|
||||
st.push_double(d);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_bool(
|
||||
bool b,
|
||||
error_code&)
|
||||
{
|
||||
st.push_bool(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_null(error_code&)
|
||||
{
|
||||
st.push_null();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_comment_part(
|
||||
string_view,
|
||||
error_code&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
handler::
|
||||
on_comment(
|
||||
string_view, error_code&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_SHARED_RESOURCE_IPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_SHARED_RESOURCE_IPP
|
||||
|
||||
#include <boost/json/detail/shared_resource.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
// these are here so that ~memory_resource
|
||||
// is emitted in the library instead of
|
||||
// the user's TU.
|
||||
|
||||
shared_resource::
|
||||
shared_resource()
|
||||
{
|
||||
}
|
||||
|
||||
shared_resource::
|
||||
~shared_resource()
|
||||
{
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_STACK_IPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_STACK_IPP
|
||||
|
||||
#include <boost/json/detail/stack.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
stack::
|
||||
~stack()
|
||||
{
|
||||
if(base_ != buf_)
|
||||
sp_->deallocate(
|
||||
base_, cap_);
|
||||
}
|
||||
|
||||
stack::
|
||||
stack(
|
||||
storage_ptr sp,
|
||||
unsigned char* buf,
|
||||
std::size_t buf_size) noexcept
|
||||
: sp_(std::move(sp))
|
||||
, cap_(buf_size)
|
||||
, base_(buf)
|
||||
, buf_(buf)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
stack::
|
||||
reserve(std::size_t n)
|
||||
{
|
||||
if(cap_ >= n)
|
||||
return;
|
||||
auto const base = static_cast<
|
||||
unsigned char*>(sp_->allocate(n));
|
||||
if(base_)
|
||||
{
|
||||
if(size_ > 0)
|
||||
std::memcpy(base, base_, size_);
|
||||
if(base_ != buf_)
|
||||
sp_->deallocate(base_, cap_);
|
||||
}
|
||||
base_ = base;
|
||||
cap_ = n;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+487
@@ -0,0 +1,487 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
|
||||
#define BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
|
||||
|
||||
#include <boost/json/detail/string_impl.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
inline
|
||||
bool
|
||||
ptr_in_range(
|
||||
const char* first,
|
||||
const char* last,
|
||||
const char* ptr) noexcept
|
||||
{
|
||||
return std::less<const char*>()(ptr, last) &&
|
||||
std::greater_equal<const char*>()(ptr, first);
|
||||
}
|
||||
|
||||
string_impl::
|
||||
string_impl() noexcept
|
||||
{
|
||||
s_.k = short_string_;
|
||||
s_.buf[sbo_chars_] =
|
||||
static_cast<char>(
|
||||
sbo_chars_);
|
||||
s_.buf[0] = 0;
|
||||
}
|
||||
|
||||
string_impl::
|
||||
string_impl(
|
||||
std::size_t size,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
if(size <= sbo_chars_)
|
||||
{
|
||||
s_.k = short_string_;
|
||||
s_.buf[sbo_chars_] =
|
||||
static_cast<char>(
|
||||
sbo_chars_ - size);
|
||||
s_.buf[size] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_.k = kind::string;
|
||||
auto const n = growth(
|
||||
size, sbo_chars_ + 1);
|
||||
p_.t = ::new(sp->allocate(
|
||||
sizeof(table) +
|
||||
n + 1,
|
||||
alignof(table))) table{
|
||||
static_cast<
|
||||
std::uint32_t>(size),
|
||||
static_cast<
|
||||
std::uint32_t>(n)};
|
||||
data()[n] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// construct a key, unchecked
|
||||
string_impl::
|
||||
string_impl(
|
||||
key_t,
|
||||
string_view s,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
s.size() <= max_size());
|
||||
k_.k = key_string_;
|
||||
k_.n = static_cast<
|
||||
std::uint32_t>(s.size());
|
||||
k_.s = reinterpret_cast<char*>(
|
||||
sp->allocate(s.size() + 1,
|
||||
alignof(char)));
|
||||
k_.s[s.size()] = 0; // null term
|
||||
std::memcpy(&k_.s[0],
|
||||
s.data(), s.size());
|
||||
}
|
||||
|
||||
// construct a key, unchecked
|
||||
string_impl::
|
||||
string_impl(
|
||||
key_t,
|
||||
string_view s1,
|
||||
string_view s2,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
auto len = s1.size() + s2.size();
|
||||
BOOST_ASSERT(len <= max_size());
|
||||
k_.k = key_string_;
|
||||
k_.n = static_cast<
|
||||
std::uint32_t>(len);
|
||||
k_.s = reinterpret_cast<char*>(
|
||||
sp->allocate(len + 1,
|
||||
alignof(char)));
|
||||
k_.s[len] = 0; // null term
|
||||
std::memcpy(&k_.s[0],
|
||||
s1.data(), s1.size());
|
||||
std::memcpy(&k_.s[s1.size()],
|
||||
s2.data(), s2.size());
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
string_impl::
|
||||
growth(
|
||||
std::size_t new_size,
|
||||
std::size_t capacity)
|
||||
{
|
||||
if(new_size > max_size())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::string_too_large, &loc );
|
||||
}
|
||||
// growth factor 2
|
||||
if( capacity >
|
||||
max_size() - capacity)
|
||||
return static_cast<
|
||||
std::uint32_t>(max_size()); // overflow
|
||||
return static_cast<std::uint32_t>(
|
||||
(std::max)(capacity * 2, new_size));
|
||||
}
|
||||
|
||||
char*
|
||||
string_impl::
|
||||
assign(
|
||||
std::size_t new_size,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
if(new_size > capacity())
|
||||
{
|
||||
string_impl tmp(growth(
|
||||
new_size,
|
||||
capacity()), sp);
|
||||
destroy(sp);
|
||||
*this = tmp;
|
||||
}
|
||||
term(new_size);
|
||||
return data();
|
||||
}
|
||||
|
||||
char*
|
||||
string_impl::
|
||||
append(
|
||||
std::size_t n,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
if(n > max_size() - size())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::string_too_large, &loc );
|
||||
}
|
||||
if(n <= capacity() - size())
|
||||
{
|
||||
term(size() + n);
|
||||
return end() - n;
|
||||
}
|
||||
string_impl tmp(growth(
|
||||
size() + n, capacity()), sp);
|
||||
std::memcpy(
|
||||
tmp.data(), data(), size());
|
||||
tmp.term(size() + n);
|
||||
destroy(sp);
|
||||
*this = tmp;
|
||||
return end() - n;
|
||||
}
|
||||
|
||||
void
|
||||
string_impl::
|
||||
insert(
|
||||
std::size_t pos,
|
||||
const char* s,
|
||||
std::size_t n,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
const auto curr_size = size();
|
||||
if(pos > curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::out_of_range, &loc );
|
||||
}
|
||||
const auto curr_data = data();
|
||||
if(n <= capacity() - curr_size)
|
||||
{
|
||||
const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
|
||||
if (!inside || (inside && ((s - curr_data) + n <= pos)))
|
||||
{
|
||||
std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
|
||||
std::memcpy(&curr_data[pos], s, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::size_t offset = s - curr_data;
|
||||
std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
|
||||
if (offset < pos)
|
||||
{
|
||||
const std::size_t diff = pos - offset;
|
||||
std::memcpy(&curr_data[pos], &curr_data[offset], diff);
|
||||
std::memcpy(&curr_data[pos + diff], &curr_data[pos + n], n - diff);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(&curr_data[pos], &curr_data[offset + n], n);
|
||||
}
|
||||
}
|
||||
size(curr_size + n);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(n > max_size() - curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::string_too_large, &loc );
|
||||
}
|
||||
string_impl tmp(growth(
|
||||
curr_size + n, capacity()), sp);
|
||||
tmp.size(curr_size + n);
|
||||
std::memcpy(
|
||||
tmp.data(),
|
||||
curr_data,
|
||||
pos);
|
||||
std::memcpy(
|
||||
tmp.data() + pos + n,
|
||||
curr_data + pos,
|
||||
curr_size + 1 - pos);
|
||||
std::memcpy(
|
||||
tmp.data() + pos,
|
||||
s,
|
||||
n);
|
||||
destroy(sp);
|
||||
*this = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
char*
|
||||
string_impl::
|
||||
insert_unchecked(
|
||||
std::size_t pos,
|
||||
std::size_t n,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
const auto curr_size = size();
|
||||
if(pos > curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::out_of_range, &loc );
|
||||
}
|
||||
const auto curr_data = data();
|
||||
if(n <= capacity() - size())
|
||||
{
|
||||
auto const dest =
|
||||
curr_data + pos;
|
||||
std::memmove(
|
||||
dest + n,
|
||||
dest,
|
||||
curr_size + 1 - pos);
|
||||
size(curr_size + n);
|
||||
return dest;
|
||||
}
|
||||
if(n > max_size() - curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::string_too_large, &loc );
|
||||
}
|
||||
string_impl tmp(growth(
|
||||
curr_size + n, capacity()), sp);
|
||||
tmp.size(curr_size + n);
|
||||
std::memcpy(
|
||||
tmp.data(),
|
||||
curr_data,
|
||||
pos);
|
||||
std::memcpy(
|
||||
tmp.data() + pos + n,
|
||||
curr_data + pos,
|
||||
curr_size + 1 - pos);
|
||||
destroy(sp);
|
||||
*this = tmp;
|
||||
return data() + pos;
|
||||
}
|
||||
|
||||
void
|
||||
string_impl::
|
||||
replace(
|
||||
std::size_t pos,
|
||||
std::size_t n1,
|
||||
const char* s,
|
||||
std::size_t n2,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
const auto curr_size = size();
|
||||
if (pos > curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::out_of_range, &loc );
|
||||
}
|
||||
const auto curr_data = data();
|
||||
n1 = (std::min)(n1, curr_size - pos);
|
||||
const auto delta = (std::max)(n1, n2) -
|
||||
(std::min)(n1, n2);
|
||||
// if we are shrinking in size or we have enough
|
||||
// capacity, dont reallocate
|
||||
if (n1 > n2 || delta <= capacity() - curr_size)
|
||||
{
|
||||
const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
|
||||
// there is nothing to replace; return
|
||||
if (inside && s == curr_data + pos && n1 == n2)
|
||||
return;
|
||||
if (!inside || (inside && ((s - curr_data) + n2 <= pos)))
|
||||
{
|
||||
// source outside
|
||||
std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
|
||||
std::memcpy(&curr_data[pos], s, n2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// source inside
|
||||
const std::size_t offset = s - curr_data;
|
||||
if (n2 >= n1)
|
||||
{
|
||||
// grow/unchanged
|
||||
const std::size_t diff = offset <= pos + n1 ? (std::min)((pos + n1) - offset, n2) : 0;
|
||||
// shift all right of splice point by n2 - n1 to the right
|
||||
std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
|
||||
// copy all before splice point
|
||||
std::memmove(&curr_data[pos], &curr_data[offset], diff);
|
||||
// copy all after splice point
|
||||
std::memmove(&curr_data[pos + diff], &curr_data[(offset - n1) + n2 + diff], n2 - diff);
|
||||
}
|
||||
else
|
||||
{
|
||||
// shrink
|
||||
// copy all elements into place
|
||||
std::memmove(&curr_data[pos], &curr_data[offset], n2);
|
||||
// shift all elements after splice point left
|
||||
std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
|
||||
}
|
||||
}
|
||||
size((curr_size - n1) + n2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (delta > max_size() - curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::string_too_large, &loc );
|
||||
}
|
||||
// would exceed capacity, reallocate
|
||||
string_impl tmp(growth(
|
||||
curr_size + delta, capacity()), sp);
|
||||
tmp.size(curr_size + delta);
|
||||
std::memcpy(
|
||||
tmp.data(),
|
||||
curr_data,
|
||||
pos);
|
||||
std::memcpy(
|
||||
tmp.data() + pos + n2,
|
||||
curr_data + pos + n1,
|
||||
curr_size - pos - n1 + 1);
|
||||
std::memcpy(
|
||||
tmp.data() + pos,
|
||||
s,
|
||||
n2);
|
||||
destroy(sp);
|
||||
*this = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// unlike the replace overload, this function does
|
||||
// not move any characters
|
||||
char*
|
||||
string_impl::
|
||||
replace_unchecked(
|
||||
std::size_t pos,
|
||||
std::size_t n1,
|
||||
std::size_t n2,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
const auto curr_size = size();
|
||||
if(pos > curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::out_of_range, &loc );
|
||||
}
|
||||
const auto curr_data = data();
|
||||
const auto delta = (std::max)(n1, n2) -
|
||||
(std::min)(n1, n2);
|
||||
// if the size doesn't change, we don't need to
|
||||
// do anything
|
||||
if (!delta)
|
||||
return curr_data + pos;
|
||||
// if we are shrinking in size or we have enough
|
||||
// capacity, dont reallocate
|
||||
if(n1 > n2 || delta <= capacity() - curr_size)
|
||||
{
|
||||
auto const replace_pos = curr_data + pos;
|
||||
std::memmove(
|
||||
replace_pos + n2,
|
||||
replace_pos + n1,
|
||||
curr_size - pos - n1 + 1);
|
||||
size((curr_size - n1) + n2);
|
||||
return replace_pos;
|
||||
}
|
||||
if(delta > max_size() - curr_size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::string_too_large, &loc );
|
||||
}
|
||||
// would exceed capacity, reallocate
|
||||
string_impl tmp(growth(
|
||||
curr_size + delta, capacity()), sp);
|
||||
tmp.size(curr_size + delta);
|
||||
std::memcpy(
|
||||
tmp.data(),
|
||||
curr_data,
|
||||
pos);
|
||||
std::memcpy(
|
||||
tmp.data() + pos + n2,
|
||||
curr_data + pos + n1,
|
||||
curr_size - pos - n1 + 1);
|
||||
destroy(sp);
|
||||
*this = tmp;
|
||||
return data() + pos;
|
||||
}
|
||||
|
||||
void
|
||||
string_impl::
|
||||
shrink_to_fit(
|
||||
storage_ptr const& sp) noexcept
|
||||
{
|
||||
if(s_.k == short_string_)
|
||||
return;
|
||||
auto const t = p_.t;
|
||||
if(t->size <= sbo_chars_)
|
||||
{
|
||||
s_.k = short_string_;
|
||||
std::memcpy(
|
||||
s_.buf, data(), t->size);
|
||||
s_.buf[sbo_chars_] =
|
||||
static_cast<char>(
|
||||
sbo_chars_ - t->size);
|
||||
s_.buf[t->size] = 0;
|
||||
sp->deallocate(t,
|
||||
sizeof(table) +
|
||||
t->capacity + 1,
|
||||
alignof(table));
|
||||
return;
|
||||
}
|
||||
if(t->size >= t->capacity)
|
||||
return;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
string_impl tmp(t->size, sp);
|
||||
std::memcpy(
|
||||
tmp.data(),
|
||||
data(),
|
||||
size());
|
||||
destroy(sp);
|
||||
*this = tmp;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(std::exception const&)
|
||||
{
|
||||
// eat the exception
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_OBJECT_HPP
|
||||
#define BOOST_JSON_DETAIL_OBJECT_HPP
|
||||
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/string_view.hpp>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
class object;
|
||||
class value;
|
||||
class key_value_pair;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class unchecked_object
|
||||
{
|
||||
// each element is two values,
|
||||
// first one is a string key,
|
||||
// second one is the value.
|
||||
value* data_;
|
||||
std::size_t size_;
|
||||
storage_ptr const& sp_;
|
||||
|
||||
public:
|
||||
inline
|
||||
~unchecked_object();
|
||||
|
||||
unchecked_object(
|
||||
value* data,
|
||||
std::size_t size, // # of kv-pairs
|
||||
storage_ptr const& sp) noexcept
|
||||
: data_(data)
|
||||
, size_(size)
|
||||
, sp_(sp)
|
||||
{
|
||||
}
|
||||
|
||||
unchecked_object(
|
||||
unchecked_object&& other) noexcept
|
||||
: data_(other.data_)
|
||||
, size_(other.size_)
|
||||
, sp_(other.sp_)
|
||||
{
|
||||
other.data_ = nullptr;
|
||||
}
|
||||
|
||||
storage_ptr const&
|
||||
storage() const noexcept
|
||||
{
|
||||
return sp_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
value*
|
||||
release() noexcept
|
||||
{
|
||||
auto const data = data_;
|
||||
data_ = nullptr;
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
template<class CharRange>
|
||||
std::pair<key_value_pair*, std::size_t>
|
||||
find_in_object(
|
||||
object const& obj,
|
||||
CharRange key) noexcept;
|
||||
|
||||
extern template
|
||||
BOOST_JSON_DECL
|
||||
std::pair<key_value_pair*, std::size_t>
|
||||
find_in_object<string_view>(
|
||||
object const&,
|
||||
string_view key) noexcept;
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+1809
File diff suppressed because it is too large
Load Diff
+144
@@ -0,0 +1,144 @@
|
||||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
|
||||
/*
|
||||
This is a derivative work
|
||||
*/
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_RYU_DETAIL_COMMON_HPP
|
||||
#define BOOST_JSON_DETAIL_RYU_DETAIL_COMMON_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <string.h>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
namespace ryu {
|
||||
namespace detail {
|
||||
|
||||
constexpr int DOUBLE_MANTISSA_BITS = 52;
|
||||
constexpr int DOUBLE_EXPONENT_BITS = 11;
|
||||
constexpr int DOUBLE_BIAS = 1023;
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_ARM)
|
||||
#define BOOST_JSON_RYU_32_BIT_PLATFORM
|
||||
#endif
|
||||
|
||||
inline uint32_t decimalLength9(const uint32_t v) {
|
||||
// Function precondition: v is not a 10-digit number.
|
||||
// (f2s: 9 digits are sufficient for round-tripping.)
|
||||
// (d2fixed: We print 9-digit blocks.)
|
||||
BOOST_ASSERT(v < 1000000000);
|
||||
if (v >= 100000000) { return 9; }
|
||||
if (v >= 10000000) { return 8; }
|
||||
if (v >= 1000000) { return 7; }
|
||||
if (v >= 100000) { return 6; }
|
||||
if (v >= 10000) { return 5; }
|
||||
if (v >= 1000) { return 4; }
|
||||
if (v >= 100) { return 3; }
|
||||
if (v >= 10) { return 2; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns e == 0 ? 1 : ceil(log_2(5^e)).
|
||||
inline int32_t pow5bits(const int32_t e) {
|
||||
// This approximation works up to the point that the multiplication overflows at e = 3529.
|
||||
// If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater
|
||||
// than 2^9297.
|
||||
BOOST_ASSERT(e >= 0);
|
||||
BOOST_ASSERT(e <= 3528);
|
||||
return (int32_t) (((((uint32_t) e) * 1217359) >> 19) + 1);
|
||||
}
|
||||
|
||||
// Returns floor(log_10(2^e)).
|
||||
inline uint32_t log10Pow2(const int32_t e) {
|
||||
// The first value this approximation fails for is 2^1651 which is just greater than 10^297.
|
||||
BOOST_ASSERT(e >= 0);
|
||||
BOOST_ASSERT(e <= 1650);
|
||||
return (((uint32_t) e) * 78913) >> 18;
|
||||
}
|
||||
|
||||
// Returns floor(log_10(5^e)).
|
||||
inline uint32_t log10Pow5(const int32_t e) {
|
||||
// The first value this approximation fails for is 5^2621 which is just greater than 10^1832.
|
||||
BOOST_ASSERT(e >= 0);
|
||||
BOOST_ASSERT(e <= 2620);
|
||||
return (((uint32_t) e) * 732923) >> 20;
|
||||
}
|
||||
|
||||
inline int copy_special_str(char * const result, const bool sign, const bool exponent, const bool mantissa) {
|
||||
if (mantissa) {
|
||||
memcpy(result, "NaN", 3);
|
||||
return 3;
|
||||
}
|
||||
if (sign) {
|
||||
result[0] = '-';
|
||||
}
|
||||
if (exponent) {
|
||||
memcpy(result + sign, "Infinity", 8);
|
||||
return sign + 8;
|
||||
}
|
||||
memcpy(result + sign, "0E0", 3);
|
||||
return sign + 3;
|
||||
}
|
||||
|
||||
inline
|
||||
int
|
||||
copy_special_str_conforming(
|
||||
char* const result, bool sign, bool exponent, bool mantissa)
|
||||
{
|
||||
if (mantissa)
|
||||
{
|
||||
memcpy(result, "null", 4);
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (sign)
|
||||
result[0] = '-';
|
||||
|
||||
if (exponent)
|
||||
{
|
||||
memcpy(result + sign, "1e99999", 7);
|
||||
return sign + 7;
|
||||
}
|
||||
|
||||
memcpy(result + sign, "0E0", 3);
|
||||
return sign + 3;
|
||||
}
|
||||
|
||||
inline uint32_t float_to_bits(const float f) {
|
||||
uint32_t bits = 0;
|
||||
memcpy(&bits, &f, sizeof(float));
|
||||
return bits;
|
||||
}
|
||||
|
||||
inline uint64_t double_to_bits(const double d) {
|
||||
uint64_t bits = 0;
|
||||
memcpy(&bits, &d, sizeof(double));
|
||||
return bits;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ryu
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
|
||||
/*
|
||||
This is a derivative work
|
||||
*/
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_RYU_DETAIL_D2S_HPP
|
||||
#define BOOST_JSON_DETAIL_RYU_DETAIL_D2S_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/detail/ryu/detail/common.hpp>
|
||||
|
||||
// Only include the full table if we're not optimizing for size.
|
||||
#if !defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
|
||||
#include <boost/json/detail/ryu/detail/d2s_full_table.hpp>
|
||||
#endif
|
||||
#if defined(BOOST_JSON_RYU_HAS_UINT128)
|
||||
typedef __uint128_t uint128_t;
|
||||
#else
|
||||
#include <boost/json/detail/ryu/detail/d2s_intrinsics.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
namespace ryu {
|
||||
namespace detail {
|
||||
|
||||
constexpr int DOUBLE_POW5_INV_BITCOUNT = 122;
|
||||
constexpr int DOUBLE_POW5_BITCOUNT = 121;
|
||||
|
||||
#if defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
|
||||
|
||||
constexpr int POW5_TABLE_SIZE = 26;
|
||||
|
||||
inline
|
||||
std::uint64_t const
|
||||
(&DOUBLE_POW5_TABLE() noexcept)[POW5_TABLE_SIZE]
|
||||
{
|
||||
static constexpr std::uint64_t arr[26] = {
|
||||
1ull, 5ull, 25ull, 125ull, 625ull, 3125ull, 15625ull, 78125ull, 390625ull,
|
||||
1953125ull, 9765625ull, 48828125ull, 244140625ull, 1220703125ull, 6103515625ull,
|
||||
30517578125ull, 152587890625ull, 762939453125ull, 3814697265625ull,
|
||||
19073486328125ull, 95367431640625ull, 476837158203125ull,
|
||||
2384185791015625ull, 11920928955078125ull, 59604644775390625ull,
|
||||
298023223876953125ull //, 1490116119384765625ull
|
||||
};
|
||||
return arr;
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t const
|
||||
(&DOUBLE_POW5_SPLIT2() noexcept)[13][2]
|
||||
{
|
||||
static constexpr std::uint64_t arr[13][2] = {
|
||||
{ 0u, 72057594037927936u },
|
||||
{ 10376293541461622784u, 93132257461547851u },
|
||||
{ 15052517733678820785u, 120370621524202240u },
|
||||
{ 6258995034005762182u, 77787690973264271u },
|
||||
{ 14893927168346708332u, 100538234169297439u },
|
||||
{ 4272820386026678563u, 129942622070561240u },
|
||||
{ 7330497575943398595u, 83973451344588609u },
|
||||
{ 18377130505971182927u, 108533142064701048u },
|
||||
{ 10038208235822497557u, 140275798336537794u },
|
||||
{ 7017903361312433648u, 90651109995611182u },
|
||||
{ 6366496589810271835u, 117163813585596168u },
|
||||
{ 9264989777501460624u, 75715339914673581u },
|
||||
{ 17074144231291089770u, 97859783203563123u }};
|
||||
return arr;
|
||||
}
|
||||
|
||||
// Unfortunately, the results are sometimes off by one. We use an additional
|
||||
// lookup table to store those cases and adjust the result.
|
||||
inline
|
||||
std::uint32_t const
|
||||
(&POW5_OFFSETS() noexcept)[13]
|
||||
{
|
||||
static constexpr std::uint32_t arr[13] = {
|
||||
0x00000000, 0x00000000, 0x00000000, 0x033c55be, 0x03db77d8, 0x0265ffb2,
|
||||
0x00000800, 0x01a8ff56, 0x00000000, 0x0037a200, 0x00004000, 0x03fffffc,
|
||||
0x00003ffe};
|
||||
return arr;
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t const
|
||||
(&DOUBLE_POW5_INV_SPLIT2() noexcept)[13][2]
|
||||
{
|
||||
static constexpr std::uint64_t arr[13][2] = {
|
||||
{ 1u, 288230376151711744u },
|
||||
{ 7661987648932456967u, 223007451985306231u },
|
||||
{ 12652048002903177473u, 172543658669764094u },
|
||||
{ 5522544058086115566u, 266998379490113760u },
|
||||
{ 3181575136763469022u, 206579990246952687u },
|
||||
{ 4551508647133041040u, 159833525776178802u },
|
||||
{ 1116074521063664381u, 247330401473104534u },
|
||||
{ 17400360011128145022u, 191362629322552438u },
|
||||
{ 9297997190148906106u, 148059663038321393u },
|
||||
{ 11720143854957885429u, 229111231347799689u },
|
||||
{ 15401709288678291155u, 177266229209635622u },
|
||||
{ 3003071137298187333u, 274306203439684434u },
|
||||
{ 17516772882021341108u, 212234145163966538u }};
|
||||
return arr;
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint32_t const
|
||||
(&POW5_INV_OFFSETS() noexcept)[20]
|
||||
{
|
||||
static constexpr std::uint32_t arr[20] = {
|
||||
0x51505404, 0x55054514, 0x45555545, 0x05511411, 0x00505010, 0x00000004,
|
||||
0x00000000, 0x00000000, 0x55555040, 0x00505051, 0x00050040, 0x55554000,
|
||||
0x51659559, 0x00001000, 0x15000010, 0x55455555, 0x41404051, 0x00001010,
|
||||
0x00000014, 0x00000000};
|
||||
return arr;
|
||||
}
|
||||
|
||||
#if defined(BOOST_JSON_RYU_HAS_UINT128)
|
||||
|
||||
// Computes 5^i in the form required by Ryu, and stores it in the given pointer.
|
||||
inline
|
||||
void
|
||||
double_computePow5(
|
||||
const std::uint32_t i,
|
||||
std::uint64_t* const result)
|
||||
{
|
||||
const std::uint32_t base = i / POW5_TABLE_SIZE;
|
||||
const std::uint32_t base2 = base * POW5_TABLE_SIZE;
|
||||
const std::uint32_t offset = i - base2;
|
||||
const std::uint64_t* const mul = DOUBLE_POW5_SPLIT2()[base];
|
||||
if (offset == 0)
|
||||
{
|
||||
result[0] = mul[0];
|
||||
result[1] = mul[1];
|
||||
return;
|
||||
}
|
||||
const std::uint64_t m = DOUBLE_POW5_TABLE()[offset];
|
||||
const uint128_t b0 = ((uint128_t)m) * mul[0];
|
||||
const uint128_t b2 = ((uint128_t)m) * mul[1];
|
||||
const std::uint32_t delta = pow5bits(i) - pow5bits(base2);
|
||||
const uint128_t shiftedSum = (b0 >> delta) + (b2 << (64 - delta)) + ((POW5_OFFSETS()[base] >> offset) & 1);
|
||||
result[0] = (std::uint64_t)shiftedSum;
|
||||
result[1] = (std::uint64_t)(shiftedSum >> 64);
|
||||
}
|
||||
|
||||
// Computes 5^-i in the form required by Ryu, and stores it in the given pointer.
|
||||
inline
|
||||
void
|
||||
double_computeInvPow5(
|
||||
const std::uint32_t i,
|
||||
std::uint64_t* const result)
|
||||
{
|
||||
const std::uint32_t base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE;
|
||||
const std::uint32_t base2 = base * POW5_TABLE_SIZE;
|
||||
const std::uint32_t offset = base2 - i;
|
||||
const std::uint64_t* const mul = DOUBLE_POW5_INV_SPLIT2()[base]; // 1/5^base2
|
||||
if (offset == 0)
|
||||
{
|
||||
result[0] = mul[0];
|
||||
result[1] = mul[1];
|
||||
return;
|
||||
}
|
||||
const std::uint64_t m = DOUBLE_POW5_TABLE()[offset]; // 5^offset
|
||||
const uint128_t b0 = ((uint128_t)m) * (mul[0] - 1);
|
||||
const uint128_t b2 = ((uint128_t)m) * mul[1]; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i
|
||||
const std::uint32_t delta = pow5bits(base2) - pow5bits(i);
|
||||
const uint128_t shiftedSum =
|
||||
((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((POW5_INV_OFFSETS()[i / 16] >> ((i % 16) << 1)) & 3);
|
||||
result[0] = (std::uint64_t)shiftedSum;
|
||||
result[1] = (std::uint64_t)(shiftedSum >> 64);
|
||||
}
|
||||
|
||||
#else // defined(BOOST_JSON_RYU_HAS_UINT128)
|
||||
|
||||
// Computes 5^i in the form required by Ryu, and stores it in the given pointer.
|
||||
inline
|
||||
void
|
||||
double_computePow5(
|
||||
const std::uint32_t i,
|
||||
std::uint64_t* const result)
|
||||
{
|
||||
const std::uint32_t base = i / POW5_TABLE_SIZE;
|
||||
const std::uint32_t base2 = base * POW5_TABLE_SIZE;
|
||||
const std::uint32_t offset = i - base2;
|
||||
const std::uint64_t* const mul = DOUBLE_POW5_SPLIT2()[base];
|
||||
if (offset == 0)
|
||||
{
|
||||
result[0] = mul[0];
|
||||
result[1] = mul[1];
|
||||
return;
|
||||
}
|
||||
std::uint64_t const m = DOUBLE_POW5_TABLE()[offset];
|
||||
std::uint64_t high1;
|
||||
std::uint64_t const low1 = umul128(m, mul[1], &high1);
|
||||
std::uint64_t high0;
|
||||
std::uint64_t const low0 = umul128(m, mul[0], &high0);
|
||||
std::uint64_t const sum = high0 + low1;
|
||||
if (sum < high0)
|
||||
++high1; // overflow into high1
|
||||
// high1 | sum | low0
|
||||
std::uint32_t const delta = pow5bits(i) - pow5bits(base2);
|
||||
result[0] = shiftright128(low0, sum, delta) + ((POW5_OFFSETS()[base] >> offset) & 1);
|
||||
result[1] = shiftright128(sum, high1, delta);
|
||||
}
|
||||
|
||||
// Computes 5^-i in the form required by Ryu, and stores it in the given pointer.
|
||||
inline
|
||||
void
|
||||
double_computeInvPow5(
|
||||
const std::uint32_t i,
|
||||
std::uint64_t* const result)
|
||||
{
|
||||
const std::uint32_t base = (i + POW5_TABLE_SIZE - 1) / POW5_TABLE_SIZE;
|
||||
const std::uint32_t base2 = base * POW5_TABLE_SIZE;
|
||||
const std::uint32_t offset = base2 - i;
|
||||
const std::uint64_t* const mul = DOUBLE_POW5_INV_SPLIT2()[base]; // 1/5^base2
|
||||
if (offset == 0)
|
||||
{
|
||||
result[0] = mul[0];
|
||||
result[1] = mul[1];
|
||||
return;
|
||||
}
|
||||
std::uint64_t const m = DOUBLE_POW5_TABLE()[offset];
|
||||
std::uint64_t high1;
|
||||
std::uint64_t const low1 = umul128(m, mul[1], &high1);
|
||||
std::uint64_t high0;
|
||||
std::uint64_t const low0 = umul128(m, mul[0] - 1, &high0);
|
||||
std::uint64_t const sum = high0 + low1;
|
||||
if (sum < high0)
|
||||
++high1; // overflow into high1
|
||||
// high1 | sum | low0
|
||||
std::uint32_t const delta = pow5bits(base2) - pow5bits(i);
|
||||
result[0] = shiftright128(low0, sum, delta) + 1 + ((POW5_INV_OFFSETS()[i / 16] >> ((i % 16) << 1)) & 3);
|
||||
result[1] = shiftright128(sum, high1, delta);
|
||||
}
|
||||
|
||||
#endif // defined(BOOST_JSON_RYU_HAS_UINT128)
|
||||
|
||||
#endif // defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
|
||||
|
||||
} // detail
|
||||
} // ryu
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+365
@@ -0,0 +1,365 @@
|
||||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
|
||||
/*
|
||||
This is a derivative work
|
||||
*/
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_RYU_DETAIL_D2S_FULL_TABLE_HPP
|
||||
#define BOOST_JSON_DETAIL_RYU_DETAIL_D2S_FULL_TABLE_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
namespace ryu {
|
||||
|
||||
// These tables are generated by PrintDoubleLookupTable.
|
||||
inline
|
||||
std::uint64_t const
|
||||
(&DOUBLE_POW5_INV_SPLIT() noexcept)[292][2]
|
||||
{
|
||||
static constexpr std::uint64_t arr[292][2] = {
|
||||
{ 1u, 288230376151711744u }, { 3689348814741910324u, 230584300921369395u },
|
||||
{ 2951479051793528259u, 184467440737095516u }, { 17118578500402463900u, 147573952589676412u },
|
||||
{ 12632330341676300947u, 236118324143482260u }, { 10105864273341040758u, 188894659314785808u },
|
||||
{ 15463389048156653253u, 151115727451828646u }, { 17362724847566824558u, 241785163922925834u },
|
||||
{ 17579528692795369969u, 193428131138340667u }, { 6684925324752475329u, 154742504910672534u },
|
||||
{ 18074578149087781173u, 247588007857076054u }, { 18149011334012135262u, 198070406285660843u },
|
||||
{ 3451162622983977240u, 158456325028528675u }, { 5521860196774363583u, 253530120045645880u },
|
||||
{ 4417488157419490867u, 202824096036516704u }, { 7223339340677503017u, 162259276829213363u },
|
||||
{ 7867994130342094503u, 259614842926741381u }, { 2605046489531765280u, 207691874341393105u },
|
||||
{ 2084037191625412224u, 166153499473114484u }, { 10713157136084480204u, 265845599156983174u },
|
||||
{ 12259874523609494487u, 212676479325586539u }, { 13497248433629505913u, 170141183460469231u },
|
||||
{ 14216899864323388813u, 272225893536750770u }, { 11373519891458711051u, 217780714829400616u },
|
||||
{ 5409467098425058518u, 174224571863520493u }, { 4965798542738183305u, 278759314981632789u },
|
||||
{ 7661987648932456967u, 223007451985306231u }, { 2440241304404055250u, 178405961588244985u },
|
||||
{ 3904386087046488400u, 285449538541191976u }, { 17880904128604832013u, 228359630832953580u },
|
||||
{ 14304723302883865611u, 182687704666362864u }, { 15133127457049002812u, 146150163733090291u },
|
||||
{ 16834306301794583852u, 233840261972944466u }, { 9778096226693756759u, 187072209578355573u },
|
||||
{ 15201174610838826053u, 149657767662684458u }, { 2185786488890659746u, 239452428260295134u },
|
||||
{ 5437978005854438120u, 191561942608236107u }, { 15418428848909281466u, 153249554086588885u },
|
||||
{ 6222742084545298729u, 245199286538542217u }, { 16046240111861969953u, 196159429230833773u },
|
||||
{ 1768945645263844993u, 156927543384667019u }, { 10209010661905972635u, 251084069415467230u },
|
||||
{ 8167208529524778108u, 200867255532373784u }, { 10223115638361732810u, 160693804425899027u },
|
||||
{ 1599589762411131202u, 257110087081438444u }, { 4969020624670815285u, 205688069665150755u },
|
||||
{ 3975216499736652228u, 164550455732120604u }, { 13739044029062464211u, 263280729171392966u },
|
||||
{ 7301886408508061046u, 210624583337114373u }, { 13220206756290269483u, 168499666669691498u },
|
||||
{ 17462981995322520850u, 269599466671506397u }, { 6591687966774196033u, 215679573337205118u },
|
||||
{ 12652048002903177473u, 172543658669764094u }, { 9175230360419352987u, 276069853871622551u },
|
||||
{ 3650835473593572067u, 220855883097298041u }, { 17678063637842498946u, 176684706477838432u },
|
||||
{ 13527506561580357021u, 282695530364541492u }, { 3443307619780464970u, 226156424291633194u },
|
||||
{ 6443994910566282300u, 180925139433306555u }, { 5155195928453025840u, 144740111546645244u },
|
||||
{ 15627011115008661990u, 231584178474632390u }, { 12501608892006929592u, 185267342779705912u },
|
||||
{ 2622589484121723027u, 148213874223764730u }, { 4196143174594756843u, 237142198758023568u },
|
||||
{ 10735612169159626121u, 189713759006418854u }, { 12277838550069611220u, 151771007205135083u },
|
||||
{ 15955192865369467629u, 242833611528216133u }, { 1696107848069843133u, 194266889222572907u },
|
||||
{ 12424932722681605476u, 155413511378058325u }, { 1433148282581017146u, 248661618204893321u },
|
||||
{ 15903913885032455010u, 198929294563914656u }, { 9033782293284053685u, 159143435651131725u },
|
||||
{ 14454051669254485895u, 254629497041810760u }, { 11563241335403588716u, 203703597633448608u },
|
||||
{ 16629290697806691620u, 162962878106758886u }, { 781423413297334329u, 260740604970814219u },
|
||||
{ 4314487545379777786u, 208592483976651375u }, { 3451590036303822229u, 166873987181321100u },
|
||||
{ 5522544058086115566u, 266998379490113760u }, { 4418035246468892453u, 213598703592091008u },
|
||||
{ 10913125826658934609u, 170878962873672806u }, { 10082303693170474728u, 273406340597876490u },
|
||||
{ 8065842954536379782u, 218725072478301192u }, { 17520720807854834795u, 174980057982640953u },
|
||||
{ 5897060404116273733u, 279968092772225526u }, { 1028299508551108663u, 223974474217780421u },
|
||||
{ 15580034865808528224u, 179179579374224336u }, { 17549358155809824511u, 286687326998758938u },
|
||||
{ 2971440080422128639u, 229349861599007151u }, { 17134547323305344204u, 183479889279205720u },
|
||||
{ 13707637858644275364u, 146783911423364576u }, { 14553522944347019935u, 234854258277383322u },
|
||||
{ 4264120725993795302u, 187883406621906658u }, { 10789994210278856888u, 150306725297525326u },
|
||||
{ 9885293106962350374u, 240490760476040522u }, { 529536856086059653u, 192392608380832418u },
|
||||
{ 7802327114352668369u, 153914086704665934u }, { 1415676938738538420u, 246262538727465495u },
|
||||
{ 1132541550990830736u, 197010030981972396u }, { 15663428499760305882u, 157608024785577916u },
|
||||
{ 17682787970132668764u, 252172839656924666u }, { 10456881561364224688u, 201738271725539733u },
|
||||
{ 15744202878575200397u, 161390617380431786u }, { 17812026976236499989u, 258224987808690858u },
|
||||
{ 3181575136763469022u, 206579990246952687u }, { 13613306553636506187u, 165263992197562149u },
|
||||
{ 10713244041592678929u, 264422387516099439u }, { 12259944048016053467u, 211537910012879551u },
|
||||
{ 6118606423670932450u, 169230328010303641u }, { 2411072648389671274u, 270768524816485826u },
|
||||
{ 16686253377679378312u, 216614819853188660u }, { 13349002702143502650u, 173291855882550928u },
|
||||
{ 17669055508687693916u, 277266969412081485u }, { 14135244406950155133u, 221813575529665188u },
|
||||
{ 240149081334393137u, 177450860423732151u }, { 11452284974360759988u, 283921376677971441u },
|
||||
{ 5472479164746697667u, 227137101342377153u }, { 11756680961281178780u, 181709681073901722u },
|
||||
{ 2026647139541122378u, 145367744859121378u }, { 18000030682233437097u, 232588391774594204u },
|
||||
{ 18089373360528660001u, 186070713419675363u }, { 3403452244197197031u, 148856570735740291u },
|
||||
{ 16513570034941246220u, 238170513177184465u }, { 13210856027952996976u, 190536410541747572u },
|
||||
{ 3189987192878576934u, 152429128433398058u }, { 1414630693863812771u, 243886605493436893u },
|
||||
{ 8510402184574870864u, 195109284394749514u }, { 10497670562401807014u, 156087427515799611u },
|
||||
{ 9417575270359070576u, 249739884025279378u }, { 14912757845771077107u, 199791907220223502u },
|
||||
{ 4551508647133041040u, 159833525776178802u }, { 10971762650154775986u, 255733641241886083u },
|
||||
{ 16156107749607641435u, 204586912993508866u }, { 9235537384944202825u, 163669530394807093u },
|
||||
{ 11087511001168814197u, 261871248631691349u }, { 12559357615676961681u, 209496998905353079u },
|
||||
{ 13736834907283479668u, 167597599124282463u }, { 18289587036911657145u, 268156158598851941u },
|
||||
{ 10942320814787415393u, 214524926879081553u }, { 16132554281313752961u, 171619941503265242u },
|
||||
{ 11054691591134363444u, 274591906405224388u }, { 16222450902391311402u, 219673525124179510u },
|
||||
{ 12977960721913049122u, 175738820099343608u }, { 17075388340318968271u, 281182112158949773u },
|
||||
{ 2592264228029443648u, 224945689727159819u }, { 5763160197165465241u, 179956551781727855u },
|
||||
{ 9221056315464744386u, 287930482850764568u }, { 14755542681855616155u, 230344386280611654u },
|
||||
{ 15493782960226403247u, 184275509024489323u }, { 1326979923955391628u, 147420407219591459u },
|
||||
{ 9501865507812447252u, 235872651551346334u }, { 11290841220991868125u, 188698121241077067u },
|
||||
{ 1653975347309673853u, 150958496992861654u }, { 10025058185179298811u, 241533595188578646u },
|
||||
{ 4330697733401528726u, 193226876150862917u }, { 14532604630946953951u, 154581500920690333u },
|
||||
{ 1116074521063664381u, 247330401473104534u }, { 4582208431592841828u, 197864321178483627u },
|
||||
{ 14733813189500004432u, 158291456942786901u }, { 16195403473716186445u, 253266331108459042u },
|
||||
{ 5577625149489128510u, 202613064886767234u }, { 8151448934333213131u, 162090451909413787u },
|
||||
{ 16731667109675051333u, 259344723055062059u }, { 17074682502481951390u, 207475778444049647u },
|
||||
{ 6281048372501740465u, 165980622755239718u }, { 6360328581260874421u, 265568996408383549u },
|
||||
{ 8777611679750609860u, 212455197126706839u }, { 10711438158542398211u, 169964157701365471u },
|
||||
{ 9759603424184016492u, 271942652322184754u }, { 11497031554089123517u, 217554121857747803u },
|
||||
{ 16576322872755119460u, 174043297486198242u }, { 11764721337440549842u, 278469275977917188u },
|
||||
{ 16790474699436260520u, 222775420782333750u }, { 13432379759549008416u, 178220336625867000u },
|
||||
{ 3045063541568861850u, 285152538601387201u }, { 17193446092222730773u, 228122030881109760u },
|
||||
{ 13754756873778184618u, 182497624704887808u }, { 18382503128506368341u, 145998099763910246u },
|
||||
{ 3586563302416817083u, 233596959622256395u }, { 2869250641933453667u, 186877567697805116u },
|
||||
{ 17052795772514404226u, 149502054158244092u }, { 12527077977055405469u, 239203286653190548u },
|
||||
{ 17400360011128145022u, 191362629322552438u }, { 2852241564676785048u, 153090103458041951u },
|
||||
{ 15631632947708587046u, 244944165532867121u }, { 8815957543424959314u, 195955332426293697u },
|
||||
{ 18120812478965698421u, 156764265941034957u }, { 14235904707377476180u, 250822825505655932u },
|
||||
{ 4010026136418160298u, 200658260404524746u }, { 17965416168102169531u, 160526608323619796u },
|
||||
{ 2919224165770098987u, 256842573317791675u }, { 2335379332616079190u, 205474058654233340u },
|
||||
{ 1868303466092863352u, 164379246923386672u }, { 6678634360490491686u, 263006795077418675u },
|
||||
{ 5342907488392393349u, 210405436061934940u }, { 4274325990713914679u, 168324348849547952u },
|
||||
{ 10528270399884173809u, 269318958159276723u }, { 15801313949391159694u, 215455166527421378u },
|
||||
{ 1573004715287196786u, 172364133221937103u }, { 17274202803427156150u, 275782613155099364u },
|
||||
{ 17508711057483635243u, 220626090524079491u }, { 10317620031244997871u, 176500872419263593u },
|
||||
{ 12818843235250086271u, 282401395870821749u }, { 13944423402941979340u, 225921116696657399u },
|
||||
{ 14844887537095493795u, 180736893357325919u }, { 15565258844418305359u, 144589514685860735u },
|
||||
{ 6457670077359736959u, 231343223497377177u }, { 16234182506113520537u, 185074578797901741u },
|
||||
{ 9297997190148906106u, 148059663038321393u }, { 11187446689496339446u, 236895460861314229u },
|
||||
{ 12639306166338981880u, 189516368689051383u }, { 17490142562555006151u, 151613094951241106u },
|
||||
{ 2158786396894637579u, 242580951921985771u }, { 16484424376483351356u, 194064761537588616u },
|
||||
{ 9498190686444770762u, 155251809230070893u }, { 11507756283569722895u, 248402894768113429u },
|
||||
{ 12895553841597688639u, 198722315814490743u }, { 17695140702761971558u, 158977852651592594u },
|
||||
{ 17244178680193423523u, 254364564242548151u }, { 10105994129412828495u, 203491651394038521u },
|
||||
{ 4395446488788352473u, 162793321115230817u }, { 10722063196803274280u, 260469313784369307u },
|
||||
{ 1198952927958798777u, 208375451027495446u }, { 15716557601334680315u, 166700360821996356u },
|
||||
{ 17767794532651667857u, 266720577315194170u }, { 14214235626121334286u, 213376461852155336u },
|
||||
{ 7682039686155157106u, 170701169481724269u }, { 1223217053622520399u, 273121871170758831u },
|
||||
{ 15735968901865657612u, 218497496936607064u }, { 16278123936234436413u, 174797997549285651u },
|
||||
{ 219556594781725998u, 279676796078857043u }, { 7554342905309201445u, 223741436863085634u },
|
||||
{ 9732823138989271479u, 178993149490468507u }, { 815121763415193074u, 286389039184749612u },
|
||||
{ 11720143854957885429u, 229111231347799689u }, { 13065463898708218666u, 183288985078239751u },
|
||||
{ 6763022304224664610u, 146631188062591801u }, { 3442138057275642729u, 234609900900146882u },
|
||||
{ 13821756890046245153u, 187687920720117505u }, { 11057405512036996122u, 150150336576094004u },
|
||||
{ 6623802375033462826u, 240240538521750407u }, { 16367088344252501231u, 192192430817400325u },
|
||||
{ 13093670675402000985u, 153753944653920260u }, { 2503129006933649959u, 246006311446272417u },
|
||||
{ 13070549649772650937u, 196805049157017933u }, { 17835137349301941396u, 157444039325614346u },
|
||||
{ 2710778055689733971u, 251910462920982955u }, { 2168622444551787177u, 201528370336786364u },
|
||||
{ 5424246770383340065u, 161222696269429091u }, { 1300097203129523457u, 257956314031086546u },
|
||||
{ 15797473021471260058u, 206365051224869236u }, { 8948629602435097724u, 165092040979895389u },
|
||||
{ 3249760919670425388u, 264147265567832623u }, { 9978506365220160957u, 211317812454266098u },
|
||||
{ 15361502721659949412u, 169054249963412878u }, { 2442311466204457120u, 270486799941460606u },
|
||||
{ 16711244431931206989u, 216389439953168484u }, { 17058344360286875914u, 173111551962534787u },
|
||||
{ 12535955717491360170u, 276978483140055660u }, { 10028764573993088136u, 221582786512044528u },
|
||||
{ 15401709288678291155u, 177266229209635622u }, { 9885339602917624555u, 283625966735416996u },
|
||||
{ 4218922867592189321u, 226900773388333597u }, { 14443184738299482427u, 181520618710666877u },
|
||||
{ 4175850161155765295u, 145216494968533502u }, { 10370709072591134795u, 232346391949653603u },
|
||||
{ 15675264887556728482u, 185877113559722882u }, { 5161514280561562140u, 148701690847778306u },
|
||||
{ 879725219414678777u, 237922705356445290u }, { 703780175531743021u, 190338164285156232u },
|
||||
{ 11631070584651125387u, 152270531428124985u }, { 162968861732249003u, 243632850284999977u },
|
||||
{ 11198421533611530172u, 194906280227999981u }, { 5269388412147313814u, 155925024182399985u },
|
||||
{ 8431021459435702103u, 249480038691839976u }, { 3055468352806651359u, 199584030953471981u },
|
||||
{ 17201769941212962380u, 159667224762777584u }, { 16454785461715008838u, 255467559620444135u },
|
||||
{ 13163828369372007071u, 204374047696355308u }, { 17909760324981426303u, 163499238157084246u },
|
||||
{ 2830174816776909822u, 261598781051334795u }, { 2264139853421527858u, 209279024841067836u },
|
||||
{ 16568707141704863579u, 167423219872854268u }, { 4373838538276319787u, 267877151796566830u },
|
||||
{ 3499070830621055830u, 214301721437253464u }, { 6488605479238754987u, 171441377149802771u },
|
||||
{ 3003071137298187333u, 274306203439684434u }, { 6091805724580460189u, 219444962751747547u },
|
||||
{ 15941491023890099121u, 175555970201398037u }, { 10748990379256517301u, 280889552322236860u },
|
||||
{ 8599192303405213841u, 224711641857789488u }, { 14258051472207991719u, 179769313486231590u }};
|
||||
return arr;
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t const
|
||||
(&DOUBLE_POW5_SPLIT() noexcept)[326][2]
|
||||
{
|
||||
static constexpr std::uint64_t arr[326][2] = {
|
||||
{ 0u, 72057594037927936u }, { 0u, 90071992547409920u },
|
||||
{ 0u, 112589990684262400u }, { 0u, 140737488355328000u },
|
||||
{ 0u, 87960930222080000u }, { 0u, 109951162777600000u },
|
||||
{ 0u, 137438953472000000u }, { 0u, 85899345920000000u },
|
||||
{ 0u, 107374182400000000u }, { 0u, 134217728000000000u },
|
||||
{ 0u, 83886080000000000u }, { 0u, 104857600000000000u },
|
||||
{ 0u, 131072000000000000u }, { 0u, 81920000000000000u },
|
||||
{ 0u, 102400000000000000u }, { 0u, 128000000000000000u },
|
||||
{ 0u, 80000000000000000u }, { 0u, 100000000000000000u },
|
||||
{ 0u, 125000000000000000u }, { 0u, 78125000000000000u },
|
||||
{ 0u, 97656250000000000u }, { 0u, 122070312500000000u },
|
||||
{ 0u, 76293945312500000u }, { 0u, 95367431640625000u },
|
||||
{ 0u, 119209289550781250u }, { 4611686018427387904u, 74505805969238281u },
|
||||
{ 10376293541461622784u, 93132257461547851u }, { 8358680908399640576u, 116415321826934814u },
|
||||
{ 612489549322387456u, 72759576141834259u }, { 14600669991935148032u, 90949470177292823u },
|
||||
{ 13639151471491547136u, 113686837721616029u }, { 3213881284082270208u, 142108547152020037u },
|
||||
{ 4314518811765112832u, 88817841970012523u }, { 781462496279003136u, 111022302462515654u },
|
||||
{ 10200200157203529728u, 138777878078144567u }, { 13292654125893287936u, 86736173798840354u },
|
||||
{ 7392445620511834112u, 108420217248550443u }, { 4628871007212404736u, 135525271560688054u },
|
||||
{ 16728102434789916672u, 84703294725430033u }, { 7075069988205232128u, 105879118406787542u },
|
||||
{ 18067209522111315968u, 132348898008484427u }, { 8986162942105878528u, 82718061255302767u },
|
||||
{ 6621017659204960256u, 103397576569128459u }, { 3664586055578812416u, 129246970711410574u },
|
||||
{ 16125424340018921472u, 80779356694631608u }, { 1710036351314100224u, 100974195868289511u },
|
||||
{ 15972603494424788992u, 126217744835361888u }, { 9982877184015493120u, 78886090522101180u },
|
||||
{ 12478596480019366400u, 98607613152626475u }, { 10986559581596820096u, 123259516440783094u },
|
||||
{ 2254913720070624656u, 77037197775489434u }, { 12042014186943056628u, 96296497219361792u },
|
||||
{ 15052517733678820785u, 120370621524202240u }, { 9407823583549262990u, 75231638452626400u },
|
||||
{ 11759779479436578738u, 94039548065783000u }, { 14699724349295723422u, 117549435082228750u },
|
||||
{ 4575641699882439235u, 73468396926392969u }, { 10331238143280436948u, 91835496157991211u },
|
||||
{ 8302361660673158281u, 114794370197489014u }, { 1154580038986672043u, 143492962746861268u },
|
||||
{ 9944984561221445835u, 89683101716788292u }, { 12431230701526807293u, 112103877145985365u },
|
||||
{ 1703980321626345405u, 140129846432481707u }, { 17205888765512323542u, 87581154020301066u },
|
||||
{ 12283988920035628619u, 109476442525376333u }, { 1519928094762372062u, 136845553156720417u },
|
||||
{ 12479170105294952299u, 85528470722950260u }, { 15598962631618690374u, 106910588403687825u },
|
||||
{ 5663645234241199255u, 133638235504609782u }, { 17374836326682913246u, 83523897190381113u },
|
||||
{ 7883487353071477846u, 104404871487976392u }, { 9854359191339347308u, 130506089359970490u },
|
||||
{ 10770660513014479971u, 81566305849981556u }, { 13463325641268099964u, 101957882312476945u },
|
||||
{ 2994098996302961243u, 127447352890596182u }, { 15706369927971514489u, 79654595556622613u },
|
||||
{ 5797904354682229399u, 99568244445778267u }, { 2635694424925398845u, 124460305557222834u },
|
||||
{ 6258995034005762182u, 77787690973264271u }, { 3212057774079814824u, 97234613716580339u },
|
||||
{ 17850130272881932242u, 121543267145725423u }, { 18073860448192289507u, 75964541966078389u },
|
||||
{ 8757267504958198172u, 94955677457597987u }, { 6334898362770359811u, 118694596821997484u },
|
||||
{ 13182683513586250689u, 74184123013748427u }, { 11866668373555425458u, 92730153767185534u },
|
||||
{ 5609963430089506015u, 115912692208981918u }, { 17341285199088104971u, 72445432630613698u },
|
||||
{ 12453234462005355406u, 90556790788267123u }, { 10954857059079306353u, 113195988485333904u },
|
||||
{ 13693571323849132942u, 141494985606667380u }, { 17781854114260483896u, 88434366004167112u },
|
||||
{ 3780573569116053255u, 110542957505208891u }, { 114030942967678664u, 138178696881511114u },
|
||||
{ 4682955357782187069u, 86361685550944446u }, { 15077066234082509644u, 107952106938680557u },
|
||||
{ 5011274737320973344u, 134940133673350697u }, { 14661261756894078100u, 84337583545844185u },
|
||||
{ 4491519140835433913u, 105421979432305232u }, { 5614398926044292391u, 131777474290381540u },
|
||||
{ 12732371365632458552u, 82360921431488462u }, { 6692092170185797382u, 102951151789360578u },
|
||||
{ 17588487249587022536u, 128688939736700722u }, { 15604490549419276989u, 80430587335437951u },
|
||||
{ 14893927168346708332u, 100538234169297439u }, { 14005722942005997511u, 125672792711621799u },
|
||||
{ 15671105866394830300u, 78545495444763624u }, { 1142138259283986260u, 98181869305954531u },
|
||||
{ 15262730879387146537u, 122727336632443163u }, { 7233363790403272633u, 76704585395276977u },
|
||||
{ 13653390756431478696u, 95880731744096221u }, { 3231680390257184658u, 119850914680120277u },
|
||||
{ 4325643253124434363u, 74906821675075173u }, { 10018740084832930858u, 93633527093843966u },
|
||||
{ 3300053069186387764u, 117041908867304958u }, { 15897591223523656064u, 73151193042065598u },
|
||||
{ 10648616992549794273u, 91438991302581998u }, { 4087399203832467033u, 114298739128227498u },
|
||||
{ 14332621041645359599u, 142873423910284372u }, { 18181260187883125557u, 89295889943927732u },
|
||||
{ 4279831161144355331u, 111619862429909666u }, { 14573160988285219972u, 139524828037387082u },
|
||||
{ 13719911636105650386u, 87203017523366926u }, { 7926517508277287175u, 109003771904208658u },
|
||||
{ 684774848491833161u, 136254714880260823u }, { 7345513307948477581u, 85159196800163014u },
|
||||
{ 18405263671790372785u, 106448996000203767u }, { 18394893571310578077u, 133061245000254709u },
|
||||
{ 13802651491282805250u, 83163278125159193u }, { 3418256308821342851u, 103954097656448992u },
|
||||
{ 4272820386026678563u, 129942622070561240u }, { 2670512741266674102u, 81214138794100775u },
|
||||
{ 17173198981865506339u, 101517673492625968u }, { 3019754653622331308u, 126897091865782461u },
|
||||
{ 4193189667727651020u, 79310682416114038u }, { 14464859121514339583u, 99138353020142547u },
|
||||
{ 13469387883465536574u, 123922941275178184u }, { 8418367427165960359u, 77451838296986365u },
|
||||
{ 15134645302384838353u, 96814797871232956u }, { 471562554271496325u, 121018497339041196u },
|
||||
{ 9518098633274461011u, 75636560836900747u }, { 7285937273165688360u, 94545701046125934u },
|
||||
{ 18330793628311886258u, 118182126307657417u }, { 4539216990053847055u, 73863828942285886u },
|
||||
{ 14897393274422084627u, 92329786177857357u }, { 4786683537745442072u, 115412232722321697u },
|
||||
{ 14520892257159371055u, 72132645451451060u }, { 18151115321449213818u, 90165806814313825u },
|
||||
{ 8853836096529353561u, 112707258517892282u }, { 1843923083806916143u, 140884073147365353u },
|
||||
{ 12681666973447792349u, 88052545717103345u }, { 2017025661527576725u, 110065682146379182u },
|
||||
{ 11744654113764246714u, 137582102682973977u }, { 422879793461572340u, 85988814176858736u },
|
||||
{ 528599741826965425u, 107486017721073420u }, { 660749677283706782u, 134357522151341775u },
|
||||
{ 7330497575943398595u, 83973451344588609u }, { 13774807988356636147u, 104966814180735761u },
|
||||
{ 3383451930163631472u, 131208517725919702u }, { 15949715511634433382u, 82005323578699813u },
|
||||
{ 6102086334260878016u, 102506654473374767u }, { 3015921899398709616u, 128133318091718459u },
|
||||
{ 18025852251620051174u, 80083323807324036u }, { 4085571240815512351u, 100104154759155046u },
|
||||
{ 14330336087874166247u, 125130193448943807u }, { 15873989082562435760u, 78206370905589879u },
|
||||
{ 15230800334775656796u, 97757963631987349u }, { 5203442363187407284u, 122197454539984187u },
|
||||
{ 946308467778435600u, 76373409087490117u }, { 5794571603150432404u, 95466761359362646u },
|
||||
{ 16466586540792816313u, 119333451699203307u }, { 7985773578781816244u, 74583407312002067u },
|
||||
{ 5370530955049882401u, 93229259140002584u }, { 6713163693812353001u, 116536573925003230u },
|
||||
{ 18030785363914884337u, 72835358703127018u }, { 13315109668038829614u, 91044198378908773u },
|
||||
{ 2808829029766373305u, 113805247973635967u }, { 17346094342490130344u, 142256559967044958u },
|
||||
{ 6229622945628943561u, 88910349979403099u }, { 3175342663608791547u, 111137937474253874u },
|
||||
{ 13192550366365765242u, 138922421842817342u }, { 3633657960551215372u, 86826513651760839u },
|
||||
{ 18377130505971182927u, 108533142064701048u }, { 4524669058754427043u, 135666427580876311u },
|
||||
{ 9745447189362598758u, 84791517238047694u }, { 2958436949848472639u, 105989396547559618u },
|
||||
{ 12921418224165366607u, 132486745684449522u }, { 12687572408530742033u, 82804216052780951u },
|
||||
{ 11247779492236039638u, 103505270065976189u }, { 224666310012885835u, 129381587582470237u },
|
||||
{ 2446259452971747599u, 80863492239043898u }, { 12281196353069460307u, 101079365298804872u },
|
||||
{ 15351495441336825384u, 126349206623506090u }, { 14206370669262903769u, 78968254139691306u },
|
||||
{ 8534591299723853903u, 98710317674614133u }, { 15279925143082205283u, 123387897093267666u },
|
||||
{ 14161639232853766206u, 77117435683292291u }, { 13090363022639819853u, 96396794604115364u },
|
||||
{ 16362953778299774816u, 120495993255144205u }, { 12532689120651053212u, 75309995784465128u },
|
||||
{ 15665861400813816515u, 94137494730581410u }, { 10358954714162494836u, 117671868413226763u },
|
||||
{ 4168503687137865320u, 73544917758266727u }, { 598943590494943747u, 91931147197833409u },
|
||||
{ 5360365506546067587u, 114913933997291761u }, { 11312142901609972388u, 143642417496614701u },
|
||||
{ 9375932322719926695u, 89776510935384188u }, { 11719915403399908368u, 112220638669230235u },
|
||||
{ 10038208235822497557u, 140275798336537794u }, { 10885566165816448877u, 87672373960336121u },
|
||||
{ 18218643725697949000u, 109590467450420151u }, { 18161618638695048346u, 136988084313025189u },
|
||||
{ 13656854658398099168u, 85617552695640743u }, { 12459382304570236056u, 107021940869550929u },
|
||||
{ 1739169825430631358u, 133777426086938662u }, { 14922039196176308311u, 83610891304336663u },
|
||||
{ 14040862976792997485u, 104513614130420829u }, { 3716020665709083144u, 130642017663026037u },
|
||||
{ 4628355925281870917u, 81651261039391273u }, { 10397130925029726550u, 102064076299239091u },
|
||||
{ 8384727637859770284u, 127580095374048864u }, { 5240454773662356427u, 79737559608780540u },
|
||||
{ 6550568467077945534u, 99671949510975675u }, { 3576524565420044014u, 124589936888719594u },
|
||||
{ 6847013871814915412u, 77868710555449746u }, { 17782139376623420074u, 97335888194312182u },
|
||||
{ 13004302183924499284u, 121669860242890228u }, { 17351060901807587860u, 76043662651806392u },
|
||||
{ 3242082053549933210u, 95054578314757991u }, { 17887660622219580224u, 118818222893447488u },
|
||||
{ 11179787888887237640u, 74261389308404680u }, { 13974734861109047050u, 92826736635505850u },
|
||||
{ 8245046539531533005u, 116033420794382313u }, { 16682369133275677888u, 72520887996488945u },
|
||||
{ 7017903361312433648u, 90651109995611182u }, { 17995751238495317868u, 113313887494513977u },
|
||||
{ 8659630992836983623u, 141642359368142472u }, { 5412269370523114764u, 88526474605089045u },
|
||||
{ 11377022731581281359u, 110658093256361306u }, { 4997906377621825891u, 138322616570451633u },
|
||||
{ 14652906532082110942u, 86451635356532270u }, { 9092761128247862869u, 108064544195665338u },
|
||||
{ 2142579373455052779u, 135080680244581673u }, { 12868327154477877747u, 84425425152863545u },
|
||||
{ 2250350887815183471u, 105531781441079432u }, { 2812938609768979339u, 131914726801349290u },
|
||||
{ 6369772649532999991u, 82446704250843306u }, { 17185587848771025797u, 103058380313554132u },
|
||||
{ 3035240737254230630u, 128822975391942666u }, { 6508711479211282048u, 80514359619964166u },
|
||||
{ 17359261385868878368u, 100642949524955207u }, { 17087390713908710056u, 125803686906194009u },
|
||||
{ 3762090168551861929u, 78627304316371256u }, { 4702612710689827411u, 98284130395464070u },
|
||||
{ 15101637925217060072u, 122855162994330087u }, { 16356052730901744401u, 76784476871456304u },
|
||||
{ 1998321839917628885u, 95980596089320381u }, { 7109588318324424010u, 119975745111650476u },
|
||||
{ 13666864735807540814u, 74984840694781547u }, { 12471894901332038114u, 93731050868476934u },
|
||||
{ 6366496589810271835u, 117163813585596168u }, { 3979060368631419896u, 73227383490997605u },
|
||||
{ 9585511479216662775u, 91534229363747006u }, { 2758517312166052660u, 114417786704683758u },
|
||||
{ 12671518677062341634u, 143022233380854697u }, { 1002170145522881665u, 89388895863034186u },
|
||||
{ 10476084718758377889u, 111736119828792732u }, { 13095105898447972362u, 139670149785990915u },
|
||||
{ 5878598177316288774u, 87293843616244322u }, { 16571619758500136775u, 109117304520305402u },
|
||||
{ 11491152661270395161u, 136396630650381753u }, { 264441385652915120u, 85247894156488596u },
|
||||
{ 330551732066143900u, 106559867695610745u }, { 5024875683510067779u, 133199834619513431u },
|
||||
{ 10058076329834874218u, 83249896637195894u }, { 3349223375438816964u, 104062370796494868u },
|
||||
{ 4186529219298521205u, 130077963495618585u }, { 14145795808130045513u, 81298727184761615u },
|
||||
{ 13070558741735168987u, 101623408980952019u }, { 11726512408741573330u, 127029261226190024u },
|
||||
{ 7329070255463483331u, 79393288266368765u }, { 13773023837756742068u, 99241610332960956u },
|
||||
{ 17216279797195927585u, 124052012916201195u }, { 8454331864033760789u, 77532508072625747u },
|
||||
{ 5956228811614813082u, 96915635090782184u }, { 7445286014518516353u, 121144543863477730u },
|
||||
{ 9264989777501460624u, 75715339914673581u }, { 16192923240304213684u, 94644174893341976u },
|
||||
{ 1794409976670715490u, 118305218616677471u }, { 8039035263060279037u, 73940761635423419u },
|
||||
{ 5437108060397960892u, 92425952044279274u }, { 16019757112352226923u, 115532440055349092u },
|
||||
{ 788976158365366019u, 72207775034593183u }, { 14821278253238871236u, 90259718793241478u },
|
||||
{ 9303225779693813237u, 112824648491551848u }, { 11629032224617266546u, 141030810614439810u },
|
||||
{ 11879831158813179495u, 88144256634024881u }, { 1014730893234310657u, 110180320792531102u },
|
||||
{ 10491785653397664129u, 137725400990663877u }, { 8863209042587234033u, 86078375619164923u },
|
||||
{ 6467325284806654637u, 107597969523956154u }, { 17307528642863094104u, 134497461904945192u },
|
||||
{ 10817205401789433815u, 84060913690590745u }, { 18133192770664180173u, 105076142113238431u },
|
||||
{ 18054804944902837312u, 131345177641548039u }, { 18201782118205355176u, 82090736025967524u },
|
||||
{ 4305483574047142354u, 102613420032459406u }, { 14605226504413703751u, 128266775040574257u },
|
||||
{ 2210737537617482988u, 80166734400358911u }, { 16598479977304017447u, 100208418000448638u },
|
||||
{ 11524727934775246001u, 125260522500560798u }, { 2591268940807140847u, 78287826562850499u },
|
||||
{ 17074144231291089770u, 97859783203563123u }, { 16730994270686474309u, 122324729004453904u },
|
||||
{ 10456871419179046443u, 76452955627783690u }, { 3847717237119032246u, 95566194534729613u },
|
||||
{ 9421332564826178211u, 119457743168412016u }, { 5888332853016361382u, 74661089480257510u },
|
||||
{ 16583788103125227536u, 93326361850321887u }, { 16118049110479146516u, 116657952312902359u },
|
||||
{ 16991309721690548428u, 72911220195563974u }, { 12015765115258409727u, 91139025244454968u },
|
||||
{ 15019706394073012159u, 113923781555568710u }, { 9551260955736489391u, 142404726944460888u },
|
||||
{ 5969538097335305869u, 89002954340288055u }, { 2850236603241744433u, 111253692925360069u }};
|
||||
return arr;
|
||||
}
|
||||
|
||||
} // ryu
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
|
||||
/*
|
||||
This is a derivative work
|
||||
*/
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_RYU_DETAIL_D2S_INTRINSICS_HPP
|
||||
#define BOOST_JSON_DETAIL_RYU_DETAIL_D2S_INTRINSICS_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
// This sets BOOST_JSON_RYU_32_BIT_PLATFORM as a side effect if applicable.
|
||||
#include <boost/json/detail/ryu/detail/common.hpp>
|
||||
|
||||
#if defined(BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
namespace ryu {
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS)
|
||||
|
||||
inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
|
||||
return _umul128(a, b, productHi);
|
||||
}
|
||||
|
||||
inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
|
||||
// For the __shiftright128 intrinsic, the shift value is always
|
||||
// modulo 64.
|
||||
// In the current implementation of the double-precision version
|
||||
// of Ryu, the shift value is always < 64. (In the case
|
||||
// RYU_OPTIMIZE_SIZE == 0, the shift value is in the range [49, 58].
|
||||
// Otherwise in the range [2, 59].)
|
||||
// Check this here in case a future change requires larger shift
|
||||
// values. In this case this function needs to be adjusted.
|
||||
BOOST_ASSERT(dist < 64);
|
||||
return __shiftright128(lo, hi, (unsigned char) dist);
|
||||
}
|
||||
|
||||
#else // defined(HAS_64_BIT_INTRINSICS)
|
||||
|
||||
inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
|
||||
// The casts here help MSVC to avoid calls to the __allmul library function.
|
||||
const uint32_t aLo = (uint32_t)a;
|
||||
const uint32_t aHi = (uint32_t)(a >> 32);
|
||||
const uint32_t bLo = (uint32_t)b;
|
||||
const uint32_t bHi = (uint32_t)(b >> 32);
|
||||
|
||||
const uint64_t b00 = (uint64_t)aLo * bLo;
|
||||
const uint64_t b01 = (uint64_t)aLo * bHi;
|
||||
const uint64_t b10 = (uint64_t)aHi * bLo;
|
||||
const uint64_t b11 = (uint64_t)aHi * bHi;
|
||||
|
||||
const uint32_t b00Lo = (uint32_t)b00;
|
||||
const uint32_t b00Hi = (uint32_t)(b00 >> 32);
|
||||
|
||||
const uint64_t mid1 = b10 + b00Hi;
|
||||
const uint32_t mid1Lo = (uint32_t)(mid1);
|
||||
const uint32_t mid1Hi = (uint32_t)(mid1 >> 32);
|
||||
|
||||
const uint64_t mid2 = b01 + mid1Lo;
|
||||
const uint32_t mid2Lo = (uint32_t)(mid2);
|
||||
const uint32_t mid2Hi = (uint32_t)(mid2 >> 32);
|
||||
|
||||
const uint64_t pHi = b11 + mid1Hi + mid2Hi;
|
||||
const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo;
|
||||
|
||||
*productHi = pHi;
|
||||
return pLo;
|
||||
}
|
||||
|
||||
inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
|
||||
// We don't need to handle the case dist >= 64 here (see above).
|
||||
BOOST_ASSERT(dist < 64);
|
||||
#if defined(RYU_OPTIMIZE_SIZE) || !defined(RYU_32_BIT_PLATFORM)
|
||||
BOOST_ASSERT(dist > 0);
|
||||
return (hi << (64 - dist)) | (lo >> dist);
|
||||
#else
|
||||
// Avoid a 64-bit shift by taking advantage of the range of shift values.
|
||||
BOOST_ASSERT(dist >= 32);
|
||||
return (hi << (64 - dist)) | ((uint32_t)(lo >> 32) >> (dist - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // defined(HAS_64_BIT_INTRINSICS)
|
||||
|
||||
#ifdef RYU_32_BIT_PLATFORM
|
||||
|
||||
// Returns the high 64 bits of the 128-bit product of a and b.
|
||||
inline uint64_t umulh(const uint64_t a, const uint64_t b) {
|
||||
// Reuse the umul128 implementation.
|
||||
// Optimizers will likely eliminate the instructions used to compute the
|
||||
// low part of the product.
|
||||
uint64_t hi;
|
||||
umul128(a, b, &hi);
|
||||
return hi;
|
||||
}
|
||||
|
||||
// On 32-bit platforms, compilers typically generate calls to library
|
||||
// functions for 64-bit divisions, even if the divisor is a constant.
|
||||
//
|
||||
// E.g.:
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=37932
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=17958
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37443
|
||||
//
|
||||
// The functions here perform division-by-constant using multiplications
|
||||
// in the same way as 64-bit compilers would do.
|
||||
//
|
||||
// NB:
|
||||
// The multipliers and shift values are the ones generated by clang x64
|
||||
// for expressions like x/5, x/10, etc.
|
||||
|
||||
inline uint64_t div5(const uint64_t x) {
|
||||
return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 2;
|
||||
}
|
||||
|
||||
inline uint64_t div10(const uint64_t x) {
|
||||
return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 3;
|
||||
}
|
||||
|
||||
inline uint64_t div100(const uint64_t x) {
|
||||
return umulh(x >> 2, 0x28F5C28F5C28F5C3u) >> 2;
|
||||
}
|
||||
|
||||
inline uint64_t div1e8(const uint64_t x) {
|
||||
return umulh(x, 0xABCC77118461CEFDu) >> 26;
|
||||
}
|
||||
|
||||
inline uint64_t div1e9(const uint64_t x) {
|
||||
return umulh(x >> 9, 0x44B82FA09B5A53u) >> 11;
|
||||
}
|
||||
|
||||
inline uint32_t mod1e9(const uint64_t x) {
|
||||
// Avoid 64-bit math as much as possible.
|
||||
// Returning (uint32_t) (x - 1000000000 * div1e9(x)) would
|
||||
// perform 32x64-bit multiplication and 64-bit subtraction.
|
||||
// x and 1000000000 * div1e9(x) are guaranteed to differ by
|
||||
// less than 10^9, so their highest 32 bits must be identical,
|
||||
// so we can truncate both sides to uint32_t before subtracting.
|
||||
// We can also simplify (uint32_t) (1000000000 * div1e9(x)).
|
||||
// We can truncate before multiplying instead of after, as multiplying
|
||||
// the highest 32 bits of div1e9(x) can't affect the lowest 32 bits.
|
||||
return ((uint32_t) x) - 1000000000 * ((uint32_t) div1e9(x));
|
||||
}
|
||||
|
||||
#else // RYU_32_BIT_PLATFORM
|
||||
|
||||
inline uint64_t div5(const uint64_t x) {
|
||||
return x / 5;
|
||||
}
|
||||
|
||||
inline uint64_t div10(const uint64_t x) {
|
||||
return x / 10;
|
||||
}
|
||||
|
||||
inline uint64_t div100(const uint64_t x) {
|
||||
return x / 100;
|
||||
}
|
||||
|
||||
inline uint64_t div1e8(const uint64_t x) {
|
||||
return x / 100000000;
|
||||
}
|
||||
|
||||
inline uint64_t div1e9(const uint64_t x) {
|
||||
return x / 1000000000;
|
||||
}
|
||||
|
||||
inline uint32_t mod1e9(const uint64_t x) {
|
||||
return (uint32_t) (x - 1000000000 * div1e9(x));
|
||||
}
|
||||
|
||||
#endif // RYU_32_BIT_PLATFORM
|
||||
|
||||
inline uint32_t pow5Factor(uint64_t value) {
|
||||
uint32_t count = 0;
|
||||
for (;;) {
|
||||
BOOST_ASSERT(value != 0);
|
||||
const uint64_t q = div5(value);
|
||||
const uint32_t r = ((uint32_t) value) - 5 * ((uint32_t) q);
|
||||
if (r != 0) {
|
||||
break;
|
||||
}
|
||||
value = q;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Returns true if value is divisible by 5^p.
|
||||
inline bool multipleOfPowerOf5(const uint64_t value, const uint32_t p) {
|
||||
// I tried a case distinction on p, but there was no performance difference.
|
||||
return pow5Factor(value) >= p;
|
||||
}
|
||||
|
||||
// Returns true if value is divisible by 2^p.
|
||||
inline bool multipleOfPowerOf2(const uint64_t value, const uint32_t p) {
|
||||
BOOST_ASSERT(value != 0);
|
||||
// return __builtin_ctzll(value) >= p;
|
||||
return (value & ((1ull << p) - 1)) == 0;
|
||||
}
|
||||
|
||||
|
||||
} // detail
|
||||
} // ryu
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
|
||||
/*
|
||||
This is a derivative work
|
||||
*/
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_RYU_DETAIL_DIGIT_TABLE_HPP
|
||||
#define BOOST_JSON_DETAIL_RYU_DETAIL_DIGIT_TABLE_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
namespace ryu {
|
||||
namespace detail {
|
||||
|
||||
// A table of all two-digit numbers. This is used to speed up decimal digit
|
||||
// generation by copying pairs of digits into the final output.
|
||||
inline
|
||||
char const
|
||||
(&DIGIT_TABLE() noexcept)[200]
|
||||
{
|
||||
static constexpr char arr[200] = {
|
||||
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
|
||||
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
|
||||
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
|
||||
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
|
||||
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
|
||||
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
|
||||
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
|
||||
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
|
||||
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
|
||||
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' };
|
||||
return arr;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ryu
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+732
@@ -0,0 +1,732 @@
|
||||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
|
||||
// Runtime compiler options:
|
||||
// -DRYU_DEBUG Generate verbose debugging output to stdout.
|
||||
//
|
||||
// -DRYU_ONLY_64_BIT_OPS Avoid using uint128_t or 64-bit intrinsics. Slower,
|
||||
// depending on your compiler.
|
||||
//
|
||||
// -DRYU_OPTIMIZE_SIZE Use smaller lookup tables. Instead of storing every
|
||||
// required power of 5, only store every 26th entry, and compute
|
||||
// intermediate values with a multiplication. This reduces the lookup table
|
||||
// size by about 10x (only one case, and only double) at the cost of some
|
||||
// performance. Currently requires MSVC intrinsics.
|
||||
|
||||
/*
|
||||
This is a derivative work
|
||||
*/
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_RYU_IMPL_D2S_IPP
|
||||
#define BOOST_JSON_DETAIL_RYU_IMPL_D2S_IPP
|
||||
|
||||
#include <boost/json/detail/ryu/ryu.hpp>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef RYU_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
// ABSL avoids uint128_t on Win32 even if __SIZEOF_INT128__ is defined.
|
||||
// Let's do the same for now.
|
||||
#if defined(__SIZEOF_INT128__) && !defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS)
|
||||
#define BOOST_JSON_RYU_HAS_UINT128
|
||||
#elif defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS) && defined(_M_X64)
|
||||
#define BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS
|
||||
#endif
|
||||
|
||||
#include <boost/json/detail/ryu/detail/common.hpp>
|
||||
#include <boost/json/detail/ryu/detail/digit_table.hpp>
|
||||
#include <boost/json/detail/ryu/detail/d2s.hpp>
|
||||
#include <boost/json/detail/ryu/detail/d2s_intrinsics.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
namespace ryu {
|
||||
namespace detail {
|
||||
|
||||
// We need a 64x128-bit multiplication and a subsequent 128-bit shift.
|
||||
// Multiplication:
|
||||
// The 64-bit factor is variable and passed in, the 128-bit factor comes
|
||||
// from a lookup table. We know that the 64-bit factor only has 55
|
||||
// significant bits (i.e., the 9 topmost bits are zeros). The 128-bit
|
||||
// factor only has 124 significant bits (i.e., the 4 topmost bits are
|
||||
// zeros).
|
||||
// Shift:
|
||||
// In principle, the multiplication result requires 55 + 124 = 179 bits to
|
||||
// represent. However, we then shift this value to the right by j, which is
|
||||
// at least j >= 115, so the result is guaranteed to fit into 179 - 115 = 64
|
||||
// bits. This means that we only need the topmost 64 significant bits of
|
||||
// the 64x128-bit multiplication.
|
||||
//
|
||||
// There are several ways to do this:
|
||||
// 1. Best case: the compiler exposes a 128-bit type.
|
||||
// We perform two 64x64-bit multiplications, add the higher 64 bits of the
|
||||
// lower result to the higher result, and shift by j - 64 bits.
|
||||
//
|
||||
// We explicitly cast from 64-bit to 128-bit, so the compiler can tell
|
||||
// that these are only 64-bit inputs, and can map these to the best
|
||||
// possible sequence of assembly instructions.
|
||||
// x64 machines happen to have matching assembly instructions for
|
||||
// 64x64-bit multiplications and 128-bit shifts.
|
||||
//
|
||||
// 2. Second best case: the compiler exposes intrinsics for the x64 assembly
|
||||
// instructions mentioned in 1.
|
||||
//
|
||||
// 3. We only have 64x64 bit instructions that return the lower 64 bits of
|
||||
// the result, i.e., we have to use plain C.
|
||||
// Our inputs are less than the full width, so we have three options:
|
||||
// a. Ignore this fact and just implement the intrinsics manually.
|
||||
// b. Split both into 31-bit pieces, which guarantees no internal overflow,
|
||||
// but requires extra work upfront (unless we change the lookup table).
|
||||
// c. Split only the first factor into 31-bit pieces, which also guarantees
|
||||
// no internal overflow, but requires extra work since the intermediate
|
||||
// results are not perfectly aligned.
|
||||
#if defined(BOOST_JSON_RYU_HAS_UINT128)
|
||||
|
||||
// Best case: use 128-bit type.
|
||||
inline
|
||||
std::uint64_t
|
||||
mulShift(
|
||||
const std::uint64_t m,
|
||||
const std::uint64_t* const mul,
|
||||
const std::int32_t j) noexcept
|
||||
{
|
||||
const uint128_t b0 = ((uint128_t) m) * mul[0];
|
||||
const uint128_t b2 = ((uint128_t) m) * mul[1];
|
||||
return (std::uint64_t) (((b0 >> 64) + b2) >> (j - 64));
|
||||
}
|
||||
|
||||
inline
|
||||
uint64_t
|
||||
mulShiftAll(
|
||||
const std::uint64_t m,
|
||||
const std::uint64_t* const mul,
|
||||
std::int32_t const j,
|
||||
std::uint64_t* const vp,
|
||||
std::uint64_t* const vm,
|
||||
const std::uint32_t mmShift) noexcept
|
||||
{
|
||||
// m <<= 2;
|
||||
// uint128_t b0 = ((uint128_t) m) * mul[0]; // 0
|
||||
// uint128_t b2 = ((uint128_t) m) * mul[1]; // 64
|
||||
//
|
||||
// uint128_t hi = (b0 >> 64) + b2;
|
||||
// uint128_t lo = b0 & 0xffffffffffffffffull;
|
||||
// uint128_t factor = (((uint128_t) mul[1]) << 64) + mul[0];
|
||||
// uint128_t vpLo = lo + (factor << 1);
|
||||
// *vp = (std::uint64_t) ((hi + (vpLo >> 64)) >> (j - 64));
|
||||
// uint128_t vmLo = lo - (factor << mmShift);
|
||||
// *vm = (std::uint64_t) ((hi + (vmLo >> 64) - (((uint128_t) 1ull) << 64)) >> (j - 64));
|
||||
// return (std::uint64_t) (hi >> (j - 64));
|
||||
*vp = mulShift(4 * m + 2, mul, j);
|
||||
*vm = mulShift(4 * m - 1 - mmShift, mul, j);
|
||||
return mulShift(4 * m, mul, j);
|
||||
}
|
||||
|
||||
#elif defined(BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS)
|
||||
|
||||
inline
|
||||
std::uint64_t
|
||||
mulShift(
|
||||
const std::uint64_t m,
|
||||
const std::uint64_t* const mul,
|
||||
const std::int32_t j) noexcept
|
||||
{
|
||||
// m is maximum 55 bits
|
||||
std::uint64_t high1; // 128
|
||||
std::uint64_t const low1 = umul128(m, mul[1], &high1); // 64
|
||||
std::uint64_t high0; // 64
|
||||
umul128(m, mul[0], &high0); // 0
|
||||
std::uint64_t const sum = high0 + low1;
|
||||
if (sum < high0)
|
||||
++high1; // overflow into high1
|
||||
return shiftright128(sum, high1, j - 64);
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t
|
||||
mulShiftAll(
|
||||
const std::uint64_t m,
|
||||
const std::uint64_t* const mul,
|
||||
const std::int32_t j,
|
||||
std::uint64_t* const vp,
|
||||
std::uint64_t* const vm,
|
||||
const std::uint32_t mmShift) noexcept
|
||||
{
|
||||
*vp = mulShift(4 * m + 2, mul, j);
|
||||
*vm = mulShift(4 * m - 1 - mmShift, mul, j);
|
||||
return mulShift(4 * m, mul, j);
|
||||
}
|
||||
|
||||
#else // !defined(BOOST_JSON_RYU_HAS_UINT128) && !defined(BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS)
|
||||
|
||||
inline
|
||||
std::uint64_t
|
||||
mulShiftAll(
|
||||
std::uint64_t m,
|
||||
const std::uint64_t* const mul,
|
||||
const std::int32_t j,
|
||||
std::uint64_t* const vp,
|
||||
std::uint64_t* const vm,
|
||||
const std::uint32_t mmShift)
|
||||
{
|
||||
m <<= 1;
|
||||
// m is maximum 55 bits
|
||||
std::uint64_t tmp;
|
||||
std::uint64_t const lo = umul128(m, mul[0], &tmp);
|
||||
std::uint64_t hi;
|
||||
std::uint64_t const mid = tmp + umul128(m, mul[1], &hi);
|
||||
hi += mid < tmp; // overflow into hi
|
||||
|
||||
const std::uint64_t lo2 = lo + mul[0];
|
||||
const std::uint64_t mid2 = mid + mul[1] + (lo2 < lo);
|
||||
const std::uint64_t hi2 = hi + (mid2 < mid);
|
||||
*vp = shiftright128(mid2, hi2, (std::uint32_t)(j - 64 - 1));
|
||||
|
||||
if (mmShift == 1)
|
||||
{
|
||||
const std::uint64_t lo3 = lo - mul[0];
|
||||
const std::uint64_t mid3 = mid - mul[1] - (lo3 > lo);
|
||||
const std::uint64_t hi3 = hi - (mid3 > mid);
|
||||
*vm = shiftright128(mid3, hi3, (std::uint32_t)(j - 64 - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::uint64_t lo3 = lo + lo;
|
||||
const std::uint64_t mid3 = mid + mid + (lo3 < lo);
|
||||
const std::uint64_t hi3 = hi + hi + (mid3 < mid);
|
||||
const std::uint64_t lo4 = lo3 - mul[0];
|
||||
const std::uint64_t mid4 = mid3 - mul[1] - (lo4 > lo3);
|
||||
const std::uint64_t hi4 = hi3 - (mid4 > mid3);
|
||||
*vm = shiftright128(mid4, hi4, (std::uint32_t)(j - 64));
|
||||
}
|
||||
|
||||
return shiftright128(mid, hi, (std::uint32_t)(j - 64 - 1));
|
||||
}
|
||||
|
||||
#endif // BOOST_JSON_RYU_HAS_64_BIT_INTRINSICS
|
||||
|
||||
inline
|
||||
std::uint32_t
|
||||
decimalLength17(
|
||||
const std::uint64_t v)
|
||||
{
|
||||
// This is slightly faster than a loop.
|
||||
// The average output length is 16.38 digits, so we check high-to-low.
|
||||
// Function precondition: v is not an 18, 19, or 20-digit number.
|
||||
// (17 digits are sufficient for round-tripping.)
|
||||
BOOST_ASSERT(v < 100000000000000000L);
|
||||
if (v >= 10000000000000000L) { return 17; }
|
||||
if (v >= 1000000000000000L) { return 16; }
|
||||
if (v >= 100000000000000L) { return 15; }
|
||||
if (v >= 10000000000000L) { return 14; }
|
||||
if (v >= 1000000000000L) { return 13; }
|
||||
if (v >= 100000000000L) { return 12; }
|
||||
if (v >= 10000000000L) { return 11; }
|
||||
if (v >= 1000000000L) { return 10; }
|
||||
if (v >= 100000000L) { return 9; }
|
||||
if (v >= 10000000L) { return 8; }
|
||||
if (v >= 1000000L) { return 7; }
|
||||
if (v >= 100000L) { return 6; }
|
||||
if (v >= 10000L) { return 5; }
|
||||
if (v >= 1000L) { return 4; }
|
||||
if (v >= 100L) { return 3; }
|
||||
if (v >= 10L) { return 2; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
// A floating decimal representing m * 10^e.
|
||||
struct floating_decimal_64
|
||||
{
|
||||
std::uint64_t mantissa;
|
||||
// Decimal exponent's range is -324 to 308
|
||||
// inclusive, and can fit in a short if needed.
|
||||
std::int32_t exponent;
|
||||
};
|
||||
|
||||
inline
|
||||
floating_decimal_64
|
||||
d2d(
|
||||
const std::uint64_t ieeeMantissa,
|
||||
const std::uint32_t ieeeExponent)
|
||||
{
|
||||
std::int32_t e2;
|
||||
std::uint64_t m2;
|
||||
if (ieeeExponent == 0)
|
||||
{
|
||||
// We subtract 2 so that the bounds computation has 2 additional bits.
|
||||
e2 = 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
|
||||
m2 = ieeeMantissa;
|
||||
}
|
||||
else
|
||||
{
|
||||
e2 = (std::int32_t)ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
|
||||
m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
|
||||
}
|
||||
const bool even = (m2 & 1) == 0;
|
||||
const bool acceptBounds = even;
|
||||
|
||||
#ifdef RYU_DEBUG
|
||||
printf("-> %" PRIu64 " * 2^%d\n", m2, e2 + 2);
|
||||
#endif
|
||||
|
||||
// Step 2: Determine the interval of valid decimal representations.
|
||||
const std::uint64_t mv = 4 * m2;
|
||||
// Implicit bool -> int conversion. True is 1, false is 0.
|
||||
const std::uint32_t mmShift = ieeeMantissa != 0 || ieeeExponent <= 1;
|
||||
// We would compute mp and mm like this:
|
||||
// uint64_t mp = 4 * m2 + 2;
|
||||
// uint64_t mm = mv - 1 - mmShift;
|
||||
|
||||
// Step 3: Convert to a decimal power base using 128-bit arithmetic.
|
||||
std::uint64_t vr, vp, vm;
|
||||
std::int32_t e10;
|
||||
bool vmIsTrailingZeros = false;
|
||||
bool vrIsTrailingZeros = false;
|
||||
if (e2 >= 0) {
|
||||
// I tried special-casing q == 0, but there was no effect on performance.
|
||||
// This expression is slightly faster than max(0, log10Pow2(e2) - 1).
|
||||
const std::uint32_t q = log10Pow2(e2) - (e2 > 3);
|
||||
e10 = (std::int32_t)q;
|
||||
const std::int32_t k = DOUBLE_POW5_INV_BITCOUNT + pow5bits((int32_t)q) - 1;
|
||||
const std::int32_t i = -e2 + (std::int32_t)q + k;
|
||||
#if defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
|
||||
uint64_t pow5[2];
|
||||
double_computeInvPow5(q, pow5);
|
||||
vr = mulShiftAll(m2, pow5, i, &vp, &vm, mmShift);
|
||||
#else
|
||||
vr = mulShiftAll(m2, DOUBLE_POW5_INV_SPLIT()[q], i, &vp, &vm, mmShift);
|
||||
#endif
|
||||
#ifdef RYU_DEBUG
|
||||
printf("%" PRIu64 " * 2^%d / 10^%u\n", mv, e2, q);
|
||||
printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
|
||||
#endif
|
||||
if (q <= 21)
|
||||
{
|
||||
// This should use q <= 22, but I think 21 is also safe. Smaller values
|
||||
// may still be safe, but it's more difficult to reason about them.
|
||||
// Only one of mp, mv, and mm can be a multiple of 5, if any.
|
||||
const std::uint32_t mvMod5 = ((std::uint32_t)mv) - 5 * ((std::uint32_t)div5(mv));
|
||||
if (mvMod5 == 0)
|
||||
{
|
||||
vrIsTrailingZeros = multipleOfPowerOf5(mv, q);
|
||||
}
|
||||
else if (acceptBounds)
|
||||
{
|
||||
// Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q
|
||||
// <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q
|
||||
// <=> true && pow5Factor(mm) >= q, since e2 >= q.
|
||||
vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Same as min(e2 + 1, pow5Factor(mp)) >= q.
|
||||
vp -= multipleOfPowerOf5(mv + 2, q);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This expression is slightly faster than max(0, log10Pow5(-e2) - 1).
|
||||
const std::uint32_t q = log10Pow5(-e2) - (-e2 > 1);
|
||||
e10 = (std::int32_t)q + e2;
|
||||
const std::int32_t i = -e2 - (std::int32_t)q;
|
||||
const std::int32_t k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
|
||||
const std::int32_t j = (std::int32_t)q - k;
|
||||
#if defined(BOOST_JSON_RYU_OPTIMIZE_SIZE)
|
||||
std::uint64_t pow5[2];
|
||||
double_computePow5(i, pow5);
|
||||
vr = mulShiftAll(m2, pow5, j, &vp, &vm, mmShift);
|
||||
#else
|
||||
vr = mulShiftAll(m2, DOUBLE_POW5_SPLIT()[i], j, &vp, &vm, mmShift);
|
||||
#endif
|
||||
#ifdef RYU_DEBUG
|
||||
printf("%" PRIu64 " * 5^%d / 10^%u\n", mv, -e2, q);
|
||||
printf("%u %d %d %d\n", q, i, k, j);
|
||||
printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
|
||||
#endif
|
||||
if (q <= 1)
|
||||
{
|
||||
// {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
|
||||
// mv = 4 * m2, so it always has at least two trailing 0 bits.
|
||||
vrIsTrailingZeros = true;
|
||||
if (acceptBounds)
|
||||
{
|
||||
// mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1.
|
||||
vmIsTrailingZeros = mmShift == 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// mp = mv + 2, so it always has at least one trailing 0 bit.
|
||||
--vp;
|
||||
}
|
||||
}
|
||||
else if (q < 63)
|
||||
{
|
||||
// TODO(ulfjack): Use a tighter bound here.
|
||||
// We want to know if the full product has at least q trailing zeros.
|
||||
// We need to compute min(p2(mv), p5(mv) - e2) >= q
|
||||
// <=> p2(mv) >= q && p5(mv) - e2 >= q
|
||||
// <=> p2(mv) >= q (because -e2 >= q)
|
||||
vrIsTrailingZeros = multipleOfPowerOf2(mv, q);
|
||||
#ifdef RYU_DEBUG
|
||||
printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef RYU_DEBUG
|
||||
printf("e10=%d\n", e10);
|
||||
printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
|
||||
printf("vm is trailing zeros=%s\n", vmIsTrailingZeros ? "true" : "false");
|
||||
printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
|
||||
#endif
|
||||
|
||||
// Step 4: Find the shortest decimal representation in the interval of valid representations.
|
||||
std::int32_t removed = 0;
|
||||
std::uint8_t lastRemovedDigit = 0;
|
||||
std::uint64_t output;
|
||||
// On average, we remove ~2 digits.
|
||||
if (vmIsTrailingZeros || vrIsTrailingZeros)
|
||||
{
|
||||
// General case, which happens rarely (~0.7%).
|
||||
for (;;)
|
||||
{
|
||||
const std::uint64_t vpDiv10 = div10(vp);
|
||||
const std::uint64_t vmDiv10 = div10(vm);
|
||||
if (vpDiv10 <= vmDiv10)
|
||||
break;
|
||||
const std::uint32_t vmMod10 = ((std::uint32_t)vm) - 10 * ((std::uint32_t)vmDiv10);
|
||||
const std::uint64_t vrDiv10 = div10(vr);
|
||||
const std::uint32_t vrMod10 = ((std::uint32_t)vr) - 10 * ((std::uint32_t)vrDiv10);
|
||||
vmIsTrailingZeros &= vmMod10 == 0;
|
||||
vrIsTrailingZeros &= lastRemovedDigit == 0;
|
||||
lastRemovedDigit = (uint8_t)vrMod10;
|
||||
vr = vrDiv10;
|
||||
vp = vpDiv10;
|
||||
vm = vmDiv10;
|
||||
++removed;
|
||||
}
|
||||
#ifdef RYU_DEBUG
|
||||
printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
|
||||
printf("d-10=%s\n", vmIsTrailingZeros ? "true" : "false");
|
||||
#endif
|
||||
if (vmIsTrailingZeros)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const std::uint64_t vmDiv10 = div10(vm);
|
||||
const std::uint32_t vmMod10 = ((std::uint32_t)vm) - 10 * ((std::uint32_t)vmDiv10);
|
||||
if (vmMod10 != 0)
|
||||
break;
|
||||
const std::uint64_t vpDiv10 = div10(vp);
|
||||
const std::uint64_t vrDiv10 = div10(vr);
|
||||
const std::uint32_t vrMod10 = ((std::uint32_t)vr) - 10 * ((std::uint32_t)vrDiv10);
|
||||
vrIsTrailingZeros &= lastRemovedDigit == 0;
|
||||
lastRemovedDigit = (uint8_t)vrMod10;
|
||||
vr = vrDiv10;
|
||||
vp = vpDiv10;
|
||||
vm = vmDiv10;
|
||||
++removed;
|
||||
}
|
||||
}
|
||||
#ifdef RYU_DEBUG
|
||||
printf("%" PRIu64 " %d\n", vr, lastRemovedDigit);
|
||||
printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
|
||||
#endif
|
||||
if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0)
|
||||
{
|
||||
// Round even if the exact number is .....50..0.
|
||||
lastRemovedDigit = 4;
|
||||
}
|
||||
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||
output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Specialized for the common case (~99.3%). Percentages below are relative to this.
|
||||
bool roundUp = false;
|
||||
const std::uint64_t vpDiv100 = div100(vp);
|
||||
const std::uint64_t vmDiv100 = div100(vm);
|
||||
if (vpDiv100 > vmDiv100)
|
||||
{
|
||||
// Optimization: remove two digits at a time (~86.2%).
|
||||
const std::uint64_t vrDiv100 = div100(vr);
|
||||
const std::uint32_t vrMod100 = ((std::uint32_t)vr) - 100 * ((std::uint32_t)vrDiv100);
|
||||
roundUp = vrMod100 >= 50;
|
||||
vr = vrDiv100;
|
||||
vp = vpDiv100;
|
||||
vm = vmDiv100;
|
||||
removed += 2;
|
||||
}
|
||||
// Loop iterations below (approximately), without optimization above:
|
||||
// 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
|
||||
// Loop iterations below (approximately), with optimization above:
|
||||
// 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
|
||||
for (;;)
|
||||
{
|
||||
const std::uint64_t vpDiv10 = div10(vp);
|
||||
const std::uint64_t vmDiv10 = div10(vm);
|
||||
if (vpDiv10 <= vmDiv10)
|
||||
break;
|
||||
const std::uint64_t vrDiv10 = div10(vr);
|
||||
const std::uint32_t vrMod10 = ((std::uint32_t)vr) - 10 * ((std::uint32_t)vrDiv10);
|
||||
roundUp = vrMod10 >= 5;
|
||||
vr = vrDiv10;
|
||||
vp = vpDiv10;
|
||||
vm = vmDiv10;
|
||||
++removed;
|
||||
}
|
||||
#ifdef RYU_DEBUG
|
||||
printf("%" PRIu64 " roundUp=%s\n", vr, roundUp ? "true" : "false");
|
||||
printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
|
||||
#endif
|
||||
// We need to take vr + 1 if vr is outside bounds or we need to round up.
|
||||
output = vr + (vr == vm || roundUp);
|
||||
}
|
||||
const std::int32_t exp = e10 + removed;
|
||||
|
||||
#ifdef RYU_DEBUG
|
||||
printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
|
||||
printf("O=%" PRIu64 "\n", output);
|
||||
printf("EXP=%d\n", exp);
|
||||
#endif
|
||||
|
||||
floating_decimal_64 fd;
|
||||
fd.exponent = exp;
|
||||
fd.mantissa = output;
|
||||
return fd;
|
||||
}
|
||||
|
||||
inline
|
||||
int
|
||||
to_chars(
|
||||
const floating_decimal_64 v,
|
||||
const bool sign,
|
||||
char* const result)
|
||||
{
|
||||
// Step 5: Print the decimal representation.
|
||||
int index = 0;
|
||||
if (sign)
|
||||
result[index++] = '-';
|
||||
|
||||
std::uint64_t output = v.mantissa;
|
||||
std::uint32_t const olength = decimalLength17(output);
|
||||
|
||||
#ifdef RYU_DEBUG
|
||||
printf("DIGITS=%" PRIu64 "\n", v.mantissa);
|
||||
printf("OLEN=%u\n", olength);
|
||||
printf("EXP=%u\n", v.exponent + olength);
|
||||
#endif
|
||||
|
||||
// Print the decimal digits.
|
||||
// The following code is equivalent to:
|
||||
// for (uint32_t i = 0; i < olength - 1; ++i) {
|
||||
// const uint32_t c = output % 10; output /= 10;
|
||||
// result[index + olength - i] = (char) ('0' + c);
|
||||
// }
|
||||
// result[index] = '0' + output % 10;
|
||||
|
||||
std::uint32_t i = 0;
|
||||
// We prefer 32-bit operations, even on 64-bit platforms.
|
||||
// We have at most 17 digits, and uint32_t can store 9 digits.
|
||||
// If output doesn't fit into uint32_t, we cut off 8 digits,
|
||||
// so the rest will fit into uint32_t.
|
||||
if ((output >> 32) != 0)
|
||||
{
|
||||
// Expensive 64-bit division.
|
||||
std::uint64_t const q = div1e8(output);
|
||||
std::uint32_t output2 = ((std::uint32_t)output) - 100000000 * ((std::uint32_t)q);
|
||||
output = q;
|
||||
|
||||
const std::uint32_t c = output2 % 10000;
|
||||
output2 /= 10000;
|
||||
const std::uint32_t d = output2 % 10000;
|
||||
const std::uint32_t c0 = (c % 100) << 1;
|
||||
const std::uint32_t c1 = (c / 100) << 1;
|
||||
const std::uint32_t d0 = (d % 100) << 1;
|
||||
const std::uint32_t d1 = (d / 100) << 1;
|
||||
std::memcpy(result + index + olength - i - 1, DIGIT_TABLE() + c0, 2);
|
||||
std::memcpy(result + index + olength - i - 3, DIGIT_TABLE() + c1, 2);
|
||||
std::memcpy(result + index + olength - i - 5, DIGIT_TABLE() + d0, 2);
|
||||
std::memcpy(result + index + olength - i - 7, DIGIT_TABLE() + d1, 2);
|
||||
i += 8;
|
||||
}
|
||||
uint32_t output2 = (std::uint32_t)output;
|
||||
while (output2 >= 10000)
|
||||
{
|
||||
#ifdef __clang__ // https://bugs.llvm.org/show_bug.cgi?id=38217
|
||||
const uint32_t c = output2 - 10000 * (output2 / 10000);
|
||||
#else
|
||||
const uint32_t c = output2 % 10000;
|
||||
#endif
|
||||
output2 /= 10000;
|
||||
const uint32_t c0 = (c % 100) << 1;
|
||||
const uint32_t c1 = (c / 100) << 1;
|
||||
memcpy(result + index + olength - i - 1, DIGIT_TABLE() + c0, 2);
|
||||
memcpy(result + index + olength - i - 3, DIGIT_TABLE() + c1, 2);
|
||||
i += 4;
|
||||
}
|
||||
if (output2 >= 100) {
|
||||
const uint32_t c = (output2 % 100) << 1;
|
||||
output2 /= 100;
|
||||
memcpy(result + index + olength - i - 1, DIGIT_TABLE() + c, 2);
|
||||
i += 2;
|
||||
}
|
||||
if (output2 >= 10) {
|
||||
const uint32_t c = output2 << 1;
|
||||
// We can't use memcpy here: the decimal dot goes between these two digits.
|
||||
result[index + olength - i] = DIGIT_TABLE()[c + 1];
|
||||
result[index] = DIGIT_TABLE()[c];
|
||||
}
|
||||
else {
|
||||
result[index] = (char)('0' + output2);
|
||||
}
|
||||
|
||||
// Print decimal point if needed.
|
||||
if (olength > 1) {
|
||||
result[index + 1] = '.';
|
||||
index += olength + 1;
|
||||
}
|
||||
else {
|
||||
++index;
|
||||
}
|
||||
|
||||
// Print the exponent.
|
||||
result[index++] = 'E';
|
||||
int32_t exp = v.exponent + (int32_t)olength - 1;
|
||||
if (exp < 0) {
|
||||
result[index++] = '-';
|
||||
exp = -exp;
|
||||
}
|
||||
|
||||
if (exp >= 100) {
|
||||
const int32_t c = exp % 10;
|
||||
memcpy(result + index, DIGIT_TABLE() + 2 * (exp / 10), 2);
|
||||
result[index + 2] = (char)('0' + c);
|
||||
index += 3;
|
||||
}
|
||||
else if (exp >= 10) {
|
||||
memcpy(result + index, DIGIT_TABLE() + 2 * exp, 2);
|
||||
index += 2;
|
||||
}
|
||||
else {
|
||||
result[index++] = (char)('0' + exp);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent,
|
||||
floating_decimal_64* const v) {
|
||||
const uint64_t m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
|
||||
const int32_t e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS;
|
||||
|
||||
if (e2 > 0) {
|
||||
// f = m2 * 2^e2 >= 2^53 is an integer.
|
||||
// Ignore this case for now.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e2 < -52) {
|
||||
// f < 1.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Since 2^52 <= m2 < 2^53 and 0 <= -e2 <= 52: 1 <= f = m2 / 2^-e2 < 2^53.
|
||||
// Test if the lower -e2 bits of the significand are 0, i.e. whether the fraction is 0.
|
||||
const uint64_t mask = (1ull << -e2) - 1;
|
||||
const uint64_t fraction = m2 & mask;
|
||||
if (fraction != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// f is an integer in the range [1, 2^53).
|
||||
// Note: mantissa might contain trailing (decimal) 0's.
|
||||
// Note: since 2^53 < 10^16, there is no need to adjust decimalLength17().
|
||||
v->mantissa = m2 >> -e2;
|
||||
v->exponent = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
int
|
||||
d2s_buffered_n(
|
||||
double f,
|
||||
char* result,
|
||||
bool allow_infinity_and_nan) noexcept
|
||||
{
|
||||
using namespace detail;
|
||||
// Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
|
||||
std::uint64_t const bits = double_to_bits(f);
|
||||
|
||||
#ifdef RYU_DEBUG
|
||||
printf("IN=");
|
||||
for (std::int32_t bit = 63; bit >= 0; --bit) {
|
||||
printf("%d", (int)((bits >> bit) & 1));
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
// Decode bits into sign, mantissa, and exponent.
|
||||
const bool ieeeSign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
|
||||
const std::uint64_t ieeeMantissa = bits & ((1ull << DOUBLE_MANTISSA_BITS) - 1);
|
||||
const std::uint32_t ieeeExponent = (std::uint32_t)((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1));
|
||||
// Case distinction; exit early for the easy cases.
|
||||
if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0)) {
|
||||
// We changed how special numbers are output by default
|
||||
if (allow_infinity_and_nan)
|
||||
return copy_special_str(result, ieeeSign, ieeeExponent != 0, ieeeMantissa != 0);
|
||||
else
|
||||
return copy_special_str_conforming(result, ieeeSign, ieeeExponent != 0, ieeeMantissa != 0);
|
||||
|
||||
}
|
||||
|
||||
floating_decimal_64 v;
|
||||
const bool isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v);
|
||||
if (isSmallInt) {
|
||||
// For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros.
|
||||
// For scientific notation we need to move these zeros into the exponent.
|
||||
// (This is not needed for fixed-point notation, so it might be beneficial to trim
|
||||
// trailing zeros in to_chars only if needed - once fixed-point notation output is implemented.)
|
||||
for (;;) {
|
||||
std::uint64_t const q = div10(v.mantissa);
|
||||
std::uint32_t const r = ((std::uint32_t) v.mantissa) - 10 * ((std::uint32_t) q);
|
||||
if (r != 0)
|
||||
break;
|
||||
v.mantissa = q;
|
||||
++v.exponent;
|
||||
}
|
||||
}
|
||||
else {
|
||||
v = d2d(ieeeMantissa, ieeeExponent);
|
||||
}
|
||||
|
||||
return to_chars(v, ieeeSign, result);
|
||||
}
|
||||
|
||||
} // ryu
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright 2018 Ulf Adams
|
||||
//
|
||||
// The contents of this file may be used under the terms of the Apache License,
|
||||
// Version 2.0.
|
||||
//
|
||||
// (See accompanying file LICENSE-Apache or copy at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0)
|
||||
//
|
||||
// Alternatively, the contents of this file may be used under the terms of
|
||||
// the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE-Boost or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, this software
|
||||
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied.
|
||||
|
||||
/*
|
||||
This is a derivative work
|
||||
*/
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_RYU_HPP
|
||||
#define BOOST_JSON_DETAIL_RYU_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
namespace ryu {
|
||||
|
||||
BOOST_JSON_DECL
|
||||
int d2s_buffered_n(
|
||||
double f, char* result, bool allow_infinity_and_nan = true) noexcept;
|
||||
|
||||
} // ryu
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// Copyright (c) 2023 Dmitry Arkhipov (grisumbras@yandex.ru)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_SBO_BUFFER_HPP
|
||||
#define BOOST_JSON_DETAIL_SBO_BUFFER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
template< std::size_t N >
|
||||
class sbo_buffer
|
||||
{
|
||||
struct size_ptr_pair
|
||||
{
|
||||
std::size_t size;
|
||||
char* ptr;
|
||||
};
|
||||
BOOST_STATIC_ASSERT( N >= sizeof(size_ptr_pair) );
|
||||
|
||||
union {
|
||||
std::array<char, N> buffer_;
|
||||
std::size_t capacity_;
|
||||
};
|
||||
char* data_ = buffer_.data();
|
||||
std::size_t size_ = 0;
|
||||
|
||||
bool
|
||||
is_small() const noexcept
|
||||
{
|
||||
return data_ == buffer_.data();
|
||||
}
|
||||
|
||||
void
|
||||
dispose()
|
||||
{
|
||||
if( is_small() )
|
||||
return;
|
||||
|
||||
delete[] data_;
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
buffer_ = {};
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
data_ = buffer_.data();
|
||||
}
|
||||
|
||||
static constexpr
|
||||
std::size_t
|
||||
max_size() noexcept
|
||||
{
|
||||
return BOOST_JSON_MAX_STRING_SIZE;
|
||||
}
|
||||
|
||||
public:
|
||||
sbo_buffer()
|
||||
: buffer_()
|
||||
{}
|
||||
|
||||
sbo_buffer( sbo_buffer&& other ) noexcept
|
||||
: size_(other.size_)
|
||||
{
|
||||
if( other.is_small() )
|
||||
{
|
||||
buffer_ = other.buffer_;
|
||||
data_ = buffer_.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
data_ = other.data_;
|
||||
other.data_ = other.buffer_.data();
|
||||
}
|
||||
BOOST_ASSERT( other.is_small() );
|
||||
}
|
||||
|
||||
sbo_buffer&
|
||||
operator=( sbo_buffer&& other ) noexcept
|
||||
{
|
||||
if( &other == this )
|
||||
return this;
|
||||
|
||||
if( other.is_small() )
|
||||
{
|
||||
buffer_ = other.buffer_;
|
||||
data_ = buffer_.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
data_ = other.data_;
|
||||
other.data_ = other.buffer_.data();
|
||||
}
|
||||
|
||||
size_ = other.size_;
|
||||
other.size_ = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~sbo_buffer()
|
||||
{
|
||||
if( !is_small() )
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
capacity() const noexcept
|
||||
{
|
||||
return is_small() ? buffer_.size() : capacity_;
|
||||
}
|
||||
|
||||
void
|
||||
reset() noexcept
|
||||
{
|
||||
dispose();
|
||||
clear();
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
grow( std::size_t size )
|
||||
{
|
||||
if( !size )
|
||||
return;
|
||||
|
||||
if( max_size() - size_ < size )
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::number_too_large, &loc );
|
||||
}
|
||||
|
||||
std::size_t const old_capacity = this->capacity();
|
||||
std::size_t new_capacity = size_ + size;
|
||||
|
||||
// growth factor 2
|
||||
if( old_capacity <= max_size() - old_capacity ) // check for overflow
|
||||
new_capacity = (std::max)(old_capacity * 2, new_capacity);
|
||||
|
||||
char* new_data = new char[new_capacity];
|
||||
std::memcpy(new_data, data_, size_);
|
||||
|
||||
dispose();
|
||||
data_ = new_data;
|
||||
capacity_ = new_capacity;
|
||||
}
|
||||
|
||||
char*
|
||||
append( char const* ptr, std::size_t size )
|
||||
{
|
||||
grow(size);
|
||||
|
||||
if(BOOST_JSON_LIKELY( size ))
|
||||
std::memcpy( data_ + size_, ptr, size );
|
||||
size_ += size;
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_JSON_DETAIL_SBO_BUFFER_HPP
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_SHARED_RESOURCE_HPP
|
||||
#define BOOST_JSON_DETAIL_SHARED_RESOURCE_HPP
|
||||
|
||||
#include <boost/json/memory_resource.hpp>
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class
|
||||
#endif
|
||||
|
||||
struct BOOST_SYMBOL_VISIBLE
|
||||
shared_resource
|
||||
: memory_resource
|
||||
{
|
||||
BOOST_JSON_DECL
|
||||
shared_resource();
|
||||
|
||||
BOOST_JSON_DECL
|
||||
~shared_resource();
|
||||
|
||||
std::atomic<std::size_t> refs{ 1 };
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class shared_resource_impl final
|
||||
: public shared_resource
|
||||
{
|
||||
T t;
|
||||
|
||||
public:
|
||||
template<class... Args>
|
||||
shared_resource_impl(
|
||||
Args&&... args)
|
||||
: t(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align) override
|
||||
{
|
||||
return t.allocate(n, align);
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t align) override
|
||||
{
|
||||
return t.deallocate(p, n, align);
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const&) const noexcept override
|
||||
{
|
||||
// VFALCO Is always false ok?
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+549
@@ -0,0 +1,549 @@
|
||||
//
|
||||
// Copyright (c) 2019 Peter Dimov (pdimov at gmail dot com),
|
||||
// Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_SSE2_HPP
|
||||
#define BOOST_JSON_DETAIL_SSE2_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/detail/utf8.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
# 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
|
||||
|
||||
template<bool AllowBadUTF8>
|
||||
inline
|
||||
const char*
|
||||
count_valid(
|
||||
char const* p,
|
||||
const char* end) noexcept
|
||||
{
|
||||
__m128i const q1 = _mm_set1_epi8( '\x22' ); // '"'
|
||||
__m128i const q2 = _mm_set1_epi8( '\\' ); // '\\'
|
||||
__m128i const q3 = _mm_set1_epi8( 0x1F );
|
||||
|
||||
while(end - p >= 16)
|
||||
{
|
||||
__m128i v1 = _mm_loadu_si128( (__m128i const*)p );
|
||||
__m128i v2 = _mm_cmpeq_epi8( v1, q1 ); // quote
|
||||
__m128i v3 = _mm_cmpeq_epi8( v1, q2 ); // backslash
|
||||
__m128i v4 = _mm_or_si128( v2, v3 ); // combine quotes and backslash
|
||||
__m128i v5 = _mm_min_epu8( v1, q3 );
|
||||
__m128i v6 = _mm_cmpeq_epi8( v5, v1 ); // controls
|
||||
__m128i v7 = _mm_or_si128( v4, v6 ); // combine with control
|
||||
|
||||
int w = _mm_movemask_epi8( v7 );
|
||||
|
||||
if( w != 0 )
|
||||
{
|
||||
int m;
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
m = __builtin_ffs( w ) - 1;
|
||||
#else
|
||||
unsigned long index;
|
||||
_BitScanForward( &index, w );
|
||||
m = index;
|
||||
#endif
|
||||
return p + m;
|
||||
}
|
||||
|
||||
p += 16;
|
||||
}
|
||||
|
||||
while(p != end)
|
||||
{
|
||||
const unsigned char c = *p;
|
||||
if(c == '\x22' || c == '\\' || c < 0x20)
|
||||
break;
|
||||
++p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
const char*
|
||||
count_valid<false>(
|
||||
char const* p,
|
||||
const char* end) noexcept
|
||||
{
|
||||
__m128i const q1 = _mm_set1_epi8( '\x22' ); // '"'
|
||||
__m128i const q2 = _mm_set1_epi8( '\\' );
|
||||
__m128i const q3 = _mm_set1_epi8( 0x20 );
|
||||
|
||||
while(end - p >= 16)
|
||||
{
|
||||
__m128i v1 = _mm_loadu_si128( (__m128i const*)p );
|
||||
|
||||
__m128i v2 = _mm_cmpeq_epi8( v1, q1 );
|
||||
__m128i v3 = _mm_cmpeq_epi8( v1, q2 );
|
||||
__m128i v4 = _mm_cmplt_epi8( v1, q3 );
|
||||
|
||||
__m128i v5 = _mm_or_si128( v2, v3 );
|
||||
__m128i v6 = _mm_or_si128( v5, v4 );
|
||||
|
||||
int w = _mm_movemask_epi8( v6 );
|
||||
|
||||
if( w != 0 )
|
||||
{
|
||||
int m;
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
m = __builtin_ffs( w ) - 1;
|
||||
#else
|
||||
unsigned long index;
|
||||
_BitScanForward( &index, w );
|
||||
m = index;
|
||||
#endif
|
||||
p += m;
|
||||
break;
|
||||
}
|
||||
|
||||
p += 16;
|
||||
}
|
||||
|
||||
while(p != end)
|
||||
{
|
||||
const unsigned char c = *p;
|
||||
if(c == '\x22' || c == '\\' || c < 0x20)
|
||||
break;
|
||||
if(c < 0x80)
|
||||
{
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
// validate utf-8
|
||||
uint16_t first = classify_utf8(c);
|
||||
uint8_t len = first & 0xFF;
|
||||
if(BOOST_JSON_UNLIKELY(end - p < len))
|
||||
break;
|
||||
if(BOOST_JSON_UNLIKELY(! is_valid_utf8(p, first)))
|
||||
break;
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<bool AllowBadUTF8>
|
||||
char const*
|
||||
count_valid(
|
||||
char const* p,
|
||||
char const* end) noexcept
|
||||
{
|
||||
while(p != end)
|
||||
{
|
||||
const unsigned char c = *p;
|
||||
if(c == '\x22' || c == '\\' || c < 0x20)
|
||||
break;
|
||||
++p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline
|
||||
char const*
|
||||
count_valid<false>(
|
||||
char const* p,
|
||||
char const* end) noexcept
|
||||
{
|
||||
while(p != end)
|
||||
{
|
||||
const unsigned char c = *p;
|
||||
if(c == '\x22' || c == '\\' || c < 0x20)
|
||||
break;
|
||||
if(c < 0x80)
|
||||
{
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
// validate utf-8
|
||||
uint16_t first = classify_utf8(c);
|
||||
uint8_t len = first & 0xFF;
|
||||
if(BOOST_JSON_UNLIKELY(end - p < len))
|
||||
break;
|
||||
if(BOOST_JSON_UNLIKELY(! is_valid_utf8(p, first)))
|
||||
break;
|
||||
p += len;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// KRYSTIAN NOTE: does not stop to validate
|
||||
// count_unescaped
|
||||
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
|
||||
inline
|
||||
size_t
|
||||
count_unescaped(
|
||||
char const* s,
|
||||
size_t n) noexcept
|
||||
{
|
||||
|
||||
__m128i const q1 = _mm_set1_epi8( '\x22' ); // '"'
|
||||
__m128i const q2 = _mm_set1_epi8( '\\' ); // '\\'
|
||||
__m128i const q3 = _mm_set1_epi8( 0x1F );
|
||||
|
||||
char const * s0 = s;
|
||||
|
||||
while( n >= 16 )
|
||||
{
|
||||
__m128i v1 = _mm_loadu_si128( (__m128i const*)s );
|
||||
__m128i v2 = _mm_cmpeq_epi8( v1, q1 ); // quote
|
||||
__m128i v3 = _mm_cmpeq_epi8( v1, q2 ); // backslash
|
||||
__m128i v4 = _mm_or_si128( v2, v3 ); // combine quotes and backslash
|
||||
__m128i v5 = _mm_min_epu8( v1, q3 );
|
||||
__m128i v6 = _mm_cmpeq_epi8( v5, v1 ); // controls
|
||||
__m128i v7 = _mm_or_si128( v4, v6 ); // combine with control
|
||||
|
||||
int w = _mm_movemask_epi8( v7 );
|
||||
|
||||
if( w != 0 )
|
||||
{
|
||||
int m;
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
m = __builtin_ffs( w ) - 1;
|
||||
#else
|
||||
unsigned long index;
|
||||
_BitScanForward( &index, w );
|
||||
m = index;
|
||||
#endif
|
||||
|
||||
s += m;
|
||||
break;
|
||||
}
|
||||
|
||||
s += 16;
|
||||
n -= 16;
|
||||
}
|
||||
|
||||
return s - s0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
count_unescaped(
|
||||
char const*,
|
||||
std::size_t) noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// count_digits
|
||||
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
|
||||
// assumes p..p+15 are valid
|
||||
inline int count_digits( char const* p ) noexcept
|
||||
{
|
||||
__m128i v1 = _mm_loadu_si128( (__m128i const*)p );
|
||||
v1 = _mm_add_epi8(v1, _mm_set1_epi8(70));
|
||||
v1 = _mm_cmplt_epi8(v1, _mm_set1_epi8(118));
|
||||
|
||||
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 = static_cast<int>(index);
|
||||
#endif
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// assumes p..p+15 are valid
|
||||
inline int count_digits( char const* p ) noexcept
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for( ; n < 16; ++n )
|
||||
{
|
||||
unsigned char const d = *p++ - '0';
|
||||
if(d > 9) break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// parse_unsigned
|
||||
|
||||
inline uint64_t parse_unsigned( uint64_t r, char const * p, std::size_t n ) noexcept
|
||||
{
|
||||
while( n >= 4 )
|
||||
{
|
||||
// faster on on clang for x86,
|
||||
// slower on gcc
|
||||
#ifdef __clang__
|
||||
r = r * 10 + p[0] - '0';
|
||||
r = r * 10 + p[1] - '0';
|
||||
r = r * 10 + p[2] - '0';
|
||||
r = r * 10 + p[3] - '0';
|
||||
#else
|
||||
uint32_t v;
|
||||
std::memcpy( &v, p, 4 );
|
||||
|
||||
v -= 0x30303030;
|
||||
|
||||
unsigned w0 = v & 0xFF;
|
||||
unsigned w1 = (v >> 8) & 0xFF;
|
||||
unsigned w2 = (v >> 16) & 0xFF;
|
||||
unsigned w3 = (v >> 24);
|
||||
|
||||
#ifdef BOOST_JSON_BIG_ENDIAN
|
||||
r = (((r * 10 + w3) * 10 + w2) * 10 + w1) * 10 + w0;
|
||||
#else
|
||||
r = (((r * 10 + w0) * 10 + w1) * 10 + w2) * 10 + w3;
|
||||
#endif
|
||||
#endif
|
||||
p += 4;
|
||||
n -= 4;
|
||||
}
|
||||
|
||||
switch( n )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
r = r * 10 + p[0] - '0';
|
||||
break;
|
||||
case 2:
|
||||
r = r * 10 + p[0] - '0';
|
||||
r = r * 10 + p[1] - '0';
|
||||
break;
|
||||
case 3:
|
||||
r = r * 10 + p[0] - '0';
|
||||
r = r * 10 + p[1] - '0';
|
||||
r = r * 10 + p[2] - '0';
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// KRYSTIAN: this function is unused
|
||||
// count_leading
|
||||
|
||||
/*
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
|
||||
// assumes p..p+15
|
||||
inline std::size_t count_leading( char const * p, char ch ) noexcept
|
||||
{
|
||||
__m128i const q1 = _mm_set1_epi8( ch );
|
||||
|
||||
__m128i v = _mm_loadu_si128( (__m128i const*)p );
|
||||
|
||||
__m128i w = _mm_cmpeq_epi8( v, q1 );
|
||||
|
||||
int m = _mm_movemask_epi8( w ) ^ 0xFFFF;
|
||||
|
||||
std::size_t 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
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// assumes p..p+15
|
||||
inline std::size_t count_leading( char const * p, char ch ) noexcept
|
||||
{
|
||||
std::size_t n = 0;
|
||||
|
||||
for( ; n < 16 && *p == ch; ++p, ++n );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
*/
|
||||
|
||||
// count_whitespace
|
||||
|
||||
#ifdef BOOST_JSON_USE_SSE2
|
||||
|
||||
inline const char* count_whitespace( char const* p, const char* end ) noexcept
|
||||
{
|
||||
if( p == end )
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
if( static_cast<unsigned char>( *p ) > 0x20 )
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
__m128i const q1 = _mm_set1_epi8( ' ' );
|
||||
__m128i const q2 = _mm_set1_epi8( '\n' );
|
||||
__m128i const q3 = _mm_set1_epi8( 4 ); // '\t' | 4 == '\r'
|
||||
__m128i const q4 = _mm_set1_epi8( '\r' );
|
||||
|
||||
while( end - p >= 16 )
|
||||
{
|
||||
__m128i v0 = _mm_loadu_si128( (__m128i const*)p );
|
||||
|
||||
__m128i w0 = _mm_or_si128(
|
||||
_mm_cmpeq_epi8( v0, q1 ),
|
||||
_mm_cmpeq_epi8( v0, q2 ));
|
||||
__m128i v1 = _mm_or_si128( v0, q3 );
|
||||
__m128i w1 = _mm_cmpeq_epi8( v1, q4 );
|
||||
__m128i w2 = _mm_or_si128( w0, w1 );
|
||||
|
||||
int m = _mm_movemask_epi8( w2 ) ^ 0xFFFF;
|
||||
|
||||
if( m != 0 )
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
std::size_t c = __builtin_ffs( m ) - 1;
|
||||
#else
|
||||
unsigned long index;
|
||||
_BitScanForward( &index, m );
|
||||
std::size_t c = index;
|
||||
#endif
|
||||
|
||||
p += c;
|
||||
return p;
|
||||
}
|
||||
|
||||
p += 16;
|
||||
}
|
||||
|
||||
while( p != end )
|
||||
{
|
||||
if( *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' )
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
++p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// slightly faster on msvc-14.2, slightly slower on clang-win
|
||||
|
||||
inline std::size_t count_whitespace( char const * p, std::size_t n ) noexcept
|
||||
{
|
||||
char const * p0 = p;
|
||||
|
||||
while( n > 0 )
|
||||
{
|
||||
char ch = *p;
|
||||
|
||||
if( ch == '\n' || ch == '\r' )
|
||||
{
|
||||
++p;
|
||||
--n;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ch != ' ' && ch != '\t' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
++p;
|
||||
--n;
|
||||
|
||||
while( n >= 16 )
|
||||
{
|
||||
std::size_t n2 = count_leading( p, ch );
|
||||
|
||||
p += n2;
|
||||
n -= n2;
|
||||
|
||||
if( n2 < 16 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p - p0;
|
||||
}
|
||||
*/
|
||||
|
||||
#else
|
||||
|
||||
inline const char* count_whitespace( char const* p, const char* end ) noexcept
|
||||
{
|
||||
|
||||
for(; p != end; ++p)
|
||||
{
|
||||
char const c = *p;
|
||||
if( c != ' ' && c != '\n' && c != '\r' && c != '\t' ) break;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_STACK_HPP
|
||||
#define BOOST_JSON_DETAIL_STACK_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
class stack
|
||||
{
|
||||
storage_ptr sp_;
|
||||
std::size_t cap_ = 0;
|
||||
std::size_t size_ = 0;
|
||||
unsigned char* base_ = nullptr;
|
||||
unsigned char* buf_ = nullptr;
|
||||
|
||||
public:
|
||||
BOOST_JSON_DECL
|
||||
~stack();
|
||||
|
||||
stack() = default;
|
||||
|
||||
stack(
|
||||
storage_ptr sp,
|
||||
unsigned char* buf,
|
||||
std::size_t buf_size) noexcept;
|
||||
|
||||
bool
|
||||
empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
void
|
||||
clear() noexcept
|
||||
{
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
reserve(std::size_t n);
|
||||
|
||||
template<class T>
|
||||
void
|
||||
push(T const& t)
|
||||
{
|
||||
auto const n = sizeof(T);
|
||||
// If this assert goes off, it
|
||||
// means the calling code did not
|
||||
// reserve enough to prevent a
|
||||
// reallocation.
|
||||
//BOOST_ASSERT(cap_ >= size_ + n);
|
||||
reserve(size_ + n);
|
||||
std::memcpy(
|
||||
base_ + size_, &t, n);
|
||||
size_ += n;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
push_unchecked(T const& t)
|
||||
{
|
||||
auto const n = sizeof(T);
|
||||
BOOST_ASSERT(size_ + n <= cap_);
|
||||
std::memcpy(
|
||||
base_ + size_, &t, n);
|
||||
size_ += n;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
peek(T& t)
|
||||
{
|
||||
auto const n = sizeof(T);
|
||||
BOOST_ASSERT(size_ >= n);
|
||||
std::memcpy(&t,
|
||||
base_ + size_ - n, n);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
pop(T& t)
|
||||
{
|
||||
auto const n = sizeof(T);
|
||||
BOOST_ASSERT(size_ >= n);
|
||||
size_ -= n;
|
||||
std::memcpy(
|
||||
&t, base_ + size_, n);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_STREAM_HPP
|
||||
#define BOOST_JSON_DETAIL_STREAM_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
class const_stream
|
||||
{
|
||||
friend class local_const_stream;
|
||||
|
||||
char const* p_;
|
||||
char const* end_;
|
||||
|
||||
public:
|
||||
const_stream() = default;
|
||||
|
||||
const_stream(
|
||||
char const* data,
|
||||
std::size_t size) noexcept
|
||||
: p_(data)
|
||||
, end_(data + size)
|
||||
{
|
||||
}
|
||||
|
||||
size_t
|
||||
used(char const* begin) const noexcept
|
||||
{
|
||||
return static_cast<
|
||||
size_t>(p_ - begin);
|
||||
}
|
||||
|
||||
size_t
|
||||
remain() const noexcept
|
||||
{
|
||||
return end_ - p_;
|
||||
}
|
||||
|
||||
char const*
|
||||
data() const noexcept
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return p_ < end_;
|
||||
}
|
||||
|
||||
// unchecked
|
||||
char
|
||||
operator*() const noexcept
|
||||
{
|
||||
BOOST_ASSERT(p_ < end_);
|
||||
return *p_;
|
||||
}
|
||||
|
||||
// unchecked
|
||||
const_stream&
|
||||
operator++() noexcept
|
||||
{
|
||||
BOOST_ASSERT(p_ < end_);
|
||||
++p_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
skip(std::size_t n) noexcept
|
||||
{
|
||||
BOOST_ASSERT(n <= remain());
|
||||
p_ += n;
|
||||
}
|
||||
|
||||
void
|
||||
skip_to(const char* p) noexcept
|
||||
{
|
||||
BOOST_ASSERT(p <= end_ && p >= p_);
|
||||
p_ = p;
|
||||
}
|
||||
};
|
||||
|
||||
class local_const_stream
|
||||
: public const_stream
|
||||
{
|
||||
const_stream& src_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
local_const_stream(
|
||||
const_stream& src) noexcept
|
||||
: const_stream(src)
|
||||
, src_(src)
|
||||
{
|
||||
}
|
||||
|
||||
~local_const_stream()
|
||||
{
|
||||
src_.p_ = p_;
|
||||
}
|
||||
|
||||
void
|
||||
clip(std::size_t n) noexcept
|
||||
{
|
||||
if(static_cast<std::size_t>(
|
||||
src_.end_ - p_) > n)
|
||||
end_ = p_ + n;
|
||||
else
|
||||
end_ = src_.end_;
|
||||
}
|
||||
};
|
||||
|
||||
class const_stream_wrapper
|
||||
{
|
||||
const char*& p_;
|
||||
const char* const end_;
|
||||
|
||||
friend class clipped_const_stream;
|
||||
public:
|
||||
const_stream_wrapper(
|
||||
const char*& p,
|
||||
const char* end)
|
||||
: p_(p)
|
||||
, end_(end)
|
||||
{
|
||||
}
|
||||
|
||||
void operator++() noexcept
|
||||
{
|
||||
++p_;
|
||||
}
|
||||
|
||||
void operator+=(std::size_t n) noexcept
|
||||
{
|
||||
p_ += n;
|
||||
}
|
||||
|
||||
void operator=(const char* p) noexcept
|
||||
{
|
||||
p_ = p;
|
||||
}
|
||||
|
||||
char operator*() const noexcept
|
||||
{
|
||||
return *p_;
|
||||
}
|
||||
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return p_ < end_;
|
||||
}
|
||||
|
||||
const char* begin() const noexcept
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
|
||||
const char* end() const noexcept
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
|
||||
std::size_t remain() const noexcept
|
||||
{
|
||||
return end_ - p_;
|
||||
}
|
||||
|
||||
std::size_t remain(const char* p) const noexcept
|
||||
{
|
||||
return end_ - p;
|
||||
}
|
||||
|
||||
std::size_t used(const char* p) const noexcept
|
||||
{
|
||||
return p_ - p;
|
||||
}
|
||||
};
|
||||
|
||||
class clipped_const_stream
|
||||
: public const_stream_wrapper
|
||||
{
|
||||
const char* clip_;
|
||||
|
||||
public:
|
||||
clipped_const_stream(
|
||||
const char*& p,
|
||||
const char* end)
|
||||
: const_stream_wrapper(p, end)
|
||||
, clip_(end)
|
||||
{
|
||||
}
|
||||
|
||||
void operator=(const char* p)
|
||||
{
|
||||
p_ = p;
|
||||
}
|
||||
|
||||
const char* end() const noexcept
|
||||
{
|
||||
return clip_;
|
||||
}
|
||||
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return p_ < clip_;
|
||||
}
|
||||
|
||||
std::size_t remain() const noexcept
|
||||
{
|
||||
return clip_ - p_;
|
||||
}
|
||||
|
||||
std::size_t remain(const char* p) const noexcept
|
||||
{
|
||||
return clip_ - p;
|
||||
}
|
||||
|
||||
void
|
||||
clip(std::size_t n) noexcept
|
||||
{
|
||||
if(static_cast<std::size_t>(
|
||||
end_ - p_) > n)
|
||||
clip_ = p_ + n;
|
||||
else
|
||||
clip_ = end_;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
class stream
|
||||
{
|
||||
friend class local_stream;
|
||||
|
||||
char* p_;
|
||||
char* end_;
|
||||
|
||||
public:
|
||||
stream(
|
||||
char* data,
|
||||
std::size_t size) noexcept
|
||||
: p_(data)
|
||||
, end_(data + size)
|
||||
{
|
||||
}
|
||||
|
||||
size_t
|
||||
used(char* begin) const noexcept
|
||||
{
|
||||
return static_cast<
|
||||
size_t>(p_ - begin);
|
||||
}
|
||||
|
||||
size_t
|
||||
remain() const noexcept
|
||||
{
|
||||
return end_ - p_;
|
||||
}
|
||||
|
||||
char*
|
||||
data() noexcept
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return p_ < end_;
|
||||
}
|
||||
|
||||
// unchecked
|
||||
char&
|
||||
operator*() noexcept
|
||||
{
|
||||
BOOST_ASSERT(p_ < end_);
|
||||
return *p_;
|
||||
}
|
||||
|
||||
// unchecked
|
||||
stream&
|
||||
operator++() noexcept
|
||||
{
|
||||
BOOST_ASSERT(p_ < end_);
|
||||
++p_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// unchecked
|
||||
void
|
||||
append(
|
||||
char const* src,
|
||||
std::size_t n) noexcept
|
||||
{
|
||||
BOOST_ASSERT(remain() >= n);
|
||||
std::memcpy(p_, src, n);
|
||||
p_ += n;
|
||||
}
|
||||
|
||||
// unchecked
|
||||
void
|
||||
append(char c) noexcept
|
||||
{
|
||||
BOOST_ASSERT(p_ < end_);
|
||||
*p_++ = c;
|
||||
}
|
||||
|
||||
void
|
||||
advance(std::size_t n) noexcept
|
||||
{
|
||||
BOOST_ASSERT(remain() >= n);
|
||||
p_ += n;
|
||||
}
|
||||
};
|
||||
|
||||
class local_stream
|
||||
: public stream
|
||||
{
|
||||
stream& src_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
local_stream(
|
||||
stream& src)
|
||||
: stream(src)
|
||||
, src_(src)
|
||||
{
|
||||
}
|
||||
|
||||
~local_stream()
|
||||
{
|
||||
src_.p_ = p_;
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+385
@@ -0,0 +1,385 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_STRING_IMPL_HPP
|
||||
#define BOOST_JSON_DETAIL_STRING_IMPL_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/kind.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/detail/value.hpp>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
class value;
|
||||
class string;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class string_impl
|
||||
{
|
||||
struct table
|
||||
{
|
||||
std::uint32_t size;
|
||||
std::uint32_t capacity;
|
||||
};
|
||||
|
||||
#if BOOST_JSON_ARCH == 64
|
||||
static constexpr std::size_t sbo_chars_ = 14;
|
||||
#elif BOOST_JSON_ARCH == 32
|
||||
static constexpr std::size_t sbo_chars_ = 10;
|
||||
#else
|
||||
# error Unknown architecture
|
||||
#endif
|
||||
|
||||
static
|
||||
constexpr
|
||||
kind
|
||||
short_string_ =
|
||||
static_cast<kind>(
|
||||
((unsigned char)
|
||||
kind::string) | 0x80);
|
||||
|
||||
static
|
||||
constexpr
|
||||
kind
|
||||
key_string_ =
|
||||
static_cast<kind>(
|
||||
((unsigned char)
|
||||
kind::string) | 0x40);
|
||||
|
||||
struct sbo
|
||||
{
|
||||
kind k; // must come first
|
||||
char buf[sbo_chars_ + 1];
|
||||
};
|
||||
|
||||
struct pointer
|
||||
{
|
||||
kind k; // must come first
|
||||
table* t;
|
||||
};
|
||||
|
||||
struct key
|
||||
{
|
||||
kind k; // must come first
|
||||
std::uint32_t n;
|
||||
char* s;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
sbo s_;
|
||||
pointer p_;
|
||||
key k_;
|
||||
};
|
||||
|
||||
#if BOOST_JSON_ARCH == 64
|
||||
BOOST_STATIC_ASSERT(sizeof(sbo) <= 16);
|
||||
BOOST_STATIC_ASSERT(sizeof(pointer) <= 16);
|
||||
BOOST_STATIC_ASSERT(sizeof(key) <= 16);
|
||||
#elif BOOST_JSON_ARCH == 32
|
||||
BOOST_STATIC_ASSERT(sizeof(sbo) <= 24);
|
||||
BOOST_STATIC_ASSERT(sizeof(pointer) <= 24);
|
||||
BOOST_STATIC_ASSERT(sizeof(key) <= 24);
|
||||
#endif
|
||||
|
||||
public:
|
||||
static
|
||||
constexpr
|
||||
std::size_t
|
||||
max_size() noexcept
|
||||
{
|
||||
// max_size depends on the address model
|
||||
using min = std::integral_constant<std::size_t,
|
||||
std::size_t(-1) - sizeof(table)>;
|
||||
return min::value < BOOST_JSON_MAX_STRING_SIZE ?
|
||||
min::value : BOOST_JSON_MAX_STRING_SIZE;
|
||||
}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
string_impl() noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
string_impl(
|
||||
std::size_t new_size,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
string_impl(
|
||||
key_t,
|
||||
string_view s,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
string_impl(
|
||||
key_t,
|
||||
string_view s1,
|
||||
string_view s2,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
string_impl(
|
||||
char** dest,
|
||||
std::size_t len,
|
||||
storage_ptr const& sp);
|
||||
|
||||
template<class InputIt>
|
||||
string_impl(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
storage_ptr const& sp,
|
||||
std::random_access_iterator_tag)
|
||||
: string_impl(last - first, sp)
|
||||
{
|
||||
char* out = data();
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1900
|
||||
while( first != last )
|
||||
*out++ = *first++;
|
||||
#else
|
||||
std::copy(first, last, out);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
string_impl(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
storage_ptr const& sp,
|
||||
std::input_iterator_tag)
|
||||
: string_impl(0, sp)
|
||||
{
|
||||
struct undo
|
||||
{
|
||||
string_impl* s;
|
||||
storage_ptr const& sp;
|
||||
|
||||
~undo()
|
||||
{
|
||||
if(s)
|
||||
s->destroy(sp);
|
||||
}
|
||||
};
|
||||
|
||||
undo u{this, sp};
|
||||
auto dest = data();
|
||||
while(first != last)
|
||||
{
|
||||
if(size() < capacity())
|
||||
size(size() + 1);
|
||||
else
|
||||
dest = append(1, sp);
|
||||
*dest++ = *first++;
|
||||
}
|
||||
term(size());
|
||||
u.s = nullptr;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return s_.k == kind::string ?
|
||||
p_.t->size :
|
||||
sbo_chars_ -
|
||||
s_.buf[sbo_chars_];
|
||||
}
|
||||
|
||||
std::size_t
|
||||
capacity() const noexcept
|
||||
{
|
||||
return s_.k == kind::string ?
|
||||
p_.t->capacity :
|
||||
sbo_chars_;
|
||||
}
|
||||
|
||||
void
|
||||
size(std::size_t n)
|
||||
{
|
||||
if(s_.k == kind::string)
|
||||
p_.t->size = static_cast<
|
||||
std::uint32_t>(n);
|
||||
else
|
||||
s_.buf[sbo_chars_] =
|
||||
static_cast<char>(
|
||||
sbo_chars_ - n);
|
||||
}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
static
|
||||
std::uint32_t
|
||||
growth(
|
||||
std::size_t new_size,
|
||||
std::size_t capacity);
|
||||
|
||||
char const*
|
||||
release_key(
|
||||
std::size_t& n) noexcept
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
k_.k == key_string_);
|
||||
n = k_.n;
|
||||
auto const s = k_.s;
|
||||
// prevent deallocate
|
||||
k_.k = short_string_;
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
destroy(
|
||||
storage_ptr const& sp) noexcept
|
||||
{
|
||||
if(s_.k == kind::string)
|
||||
{
|
||||
sp->deallocate(p_.t,
|
||||
sizeof(table) +
|
||||
p_.t->capacity + 1,
|
||||
alignof(table));
|
||||
}
|
||||
else if(s_.k != key_string_)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
s_.k == key_string_);
|
||||
// VFALCO unfortunately the key string
|
||||
// kind increases the cost of the destructor.
|
||||
// This function should be skipped when using
|
||||
// monotonic_resource.
|
||||
sp->deallocate(k_.s, k_.n + 1);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
char*
|
||||
assign(
|
||||
std::size_t new_size,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
char*
|
||||
append(
|
||||
std::size_t n,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
insert(
|
||||
std::size_t pos,
|
||||
const char* s,
|
||||
std::size_t n,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
char*
|
||||
insert_unchecked(
|
||||
std::size_t pos,
|
||||
std::size_t n,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
replace(
|
||||
std::size_t pos,
|
||||
std::size_t n1,
|
||||
const char* s,
|
||||
std::size_t n2,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
char*
|
||||
replace_unchecked(
|
||||
std::size_t pos,
|
||||
std::size_t n1,
|
||||
std::size_t n2,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
shrink_to_fit(
|
||||
storage_ptr const& sp) noexcept;
|
||||
|
||||
void
|
||||
term(std::size_t n) noexcept
|
||||
{
|
||||
if(s_.k == short_string_)
|
||||
{
|
||||
s_.buf[sbo_chars_] =
|
||||
static_cast<char>(
|
||||
sbo_chars_ - n);
|
||||
s_.buf[n] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_.t->size = static_cast<
|
||||
std::uint32_t>(n);
|
||||
data()[n] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
char*
|
||||
data() noexcept
|
||||
{
|
||||
if(s_.k == short_string_)
|
||||
return s_.buf;
|
||||
return reinterpret_cast<
|
||||
char*>(p_.t + 1);
|
||||
}
|
||||
|
||||
char const*
|
||||
data() const noexcept
|
||||
{
|
||||
if(s_.k == short_string_)
|
||||
return s_.buf;
|
||||
return reinterpret_cast<
|
||||
char const*>(p_.t + 1);
|
||||
}
|
||||
|
||||
char*
|
||||
end() noexcept
|
||||
{
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
char const*
|
||||
end() const noexcept
|
||||
{
|
||||
return data() + size();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
string_view
|
||||
to_string_view(T const& t) noexcept
|
||||
{
|
||||
return string_view(t);
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
using string_and_stringlike = std::integral_constant<bool,
|
||||
std::is_same<T, string>::value &&
|
||||
std::is_convertible<U const&, string_view>::value>;
|
||||
|
||||
template<class T, class U>
|
||||
using string_comp_op_requirement
|
||||
= typename std::enable_if<
|
||||
string_and_stringlike<T, U>::value ||
|
||||
string_and_stringlike<U, T>::value,
|
||||
bool>::type;
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_UTF8_HPP
|
||||
#define BOOST_JSON_DETAIL_UTF8_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
template<int N>
|
||||
std::uint32_t
|
||||
load_little_endian(void const* p)
|
||||
{
|
||||
std::uint32_t v = 0;
|
||||
std::memcpy(&v, p, N);
|
||||
#ifdef BOOST_JSON_BIG_ENDIAN
|
||||
v = ((v & 0xFF000000) >> 24) |
|
||||
((v & 0x00FF0000) >> 8) |
|
||||
((v & 0x0000FF00) << 8) |
|
||||
((v & 0x000000FF) << 24);
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
inline
|
||||
uint16_t
|
||||
classify_utf8(char c)
|
||||
{
|
||||
// 0x000 = invalid
|
||||
// 0x102 = 2 bytes, second byte [80, BF]
|
||||
// 0x203 = 3 bytes, second byte [A0, BF]
|
||||
// 0x303 = 3 bytes, second byte [80, BF]
|
||||
// 0x403 = 3 bytes, second byte [80, 9F]
|
||||
// 0x504 = 4 bytes, second byte [90, BF]
|
||||
// 0x604 = 4 bytes, second byte [80, BF]
|
||||
// 0x704 = 4 bytes, second byte [80, 8F]
|
||||
static constexpr uint16_t first[128]
|
||||
{
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
|
||||
0x000, 0x000, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
|
||||
0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
|
||||
0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
|
||||
0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
|
||||
0x203, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303,
|
||||
0x303, 0x303, 0x303, 0x303, 0x303, 0x403, 0x303, 0x303,
|
||||
0x504, 0x604, 0x604, 0x604, 0x704, 0x000, 0x000, 0x000,
|
||||
0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
|
||||
};
|
||||
return first[static_cast<unsigned char>(c & 0x7F)];
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_valid_utf8(const char* p, uint16_t first)
|
||||
{
|
||||
uint32_t v;
|
||||
switch(first >> 8)
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
|
||||
// 2 bytes, second byte [80, BF]
|
||||
case 1:
|
||||
v = load_little_endian<2>(p);
|
||||
return (v & 0xC000) == 0x8000;
|
||||
|
||||
// 3 bytes, second byte [A0, BF]
|
||||
case 2:
|
||||
v = load_little_endian<3>(p);
|
||||
return (v & 0xC0E000) == 0x80A000;
|
||||
|
||||
// 3 bytes, second byte [80, BF]
|
||||
case 3:
|
||||
v = load_little_endian<3>(p);
|
||||
return (v & 0xC0C000) == 0x808000;
|
||||
|
||||
// 3 bytes, second byte [80, 9F]
|
||||
case 4:
|
||||
v = load_little_endian<3>(p);
|
||||
return (v & 0xC0E000) == 0x808000;
|
||||
|
||||
// 4 bytes, second byte [90, BF]
|
||||
case 5:
|
||||
v = load_little_endian<4>(p);
|
||||
return (v & 0xC0C0FF00) + 0x7F7F7000 <= 0x2F00;
|
||||
|
||||
// 4 bytes, second byte [80, BF]
|
||||
case 6:
|
||||
v = load_little_endian<4>(p);
|
||||
return (v & 0xC0C0C000) == 0x80808000;
|
||||
|
||||
// 4 bytes, second byte [80, 8F]
|
||||
case 7:
|
||||
v = load_little_endian<4>(p);
|
||||
return (v & 0xC0C0F000) == 0x80808000;
|
||||
}
|
||||
}
|
||||
|
||||
class utf8_sequence
|
||||
{
|
||||
char seq_[4];
|
||||
uint16_t first_;
|
||||
uint8_t size_;
|
||||
|
||||
public:
|
||||
void
|
||||
save(
|
||||
const char* p,
|
||||
std::size_t remain) noexcept
|
||||
{
|
||||
first_ = classify_utf8(*p );
|
||||
if(remain >= length())
|
||||
size_ = length();
|
||||
else
|
||||
size_ = static_cast<uint8_t>(remain);
|
||||
std::memcpy(seq_, p, size_);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
length() const noexcept
|
||||
{
|
||||
return first_ & 0xFF;
|
||||
}
|
||||
|
||||
bool
|
||||
complete() const noexcept
|
||||
{
|
||||
return size_ >= length();
|
||||
}
|
||||
|
||||
// returns true if complete
|
||||
bool
|
||||
append(
|
||||
const char* p,
|
||||
std::size_t remain) noexcept
|
||||
{
|
||||
if(BOOST_JSON_UNLIKELY(needed() == 0))
|
||||
return true;
|
||||
if(BOOST_JSON_LIKELY(remain >= needed()))
|
||||
{
|
||||
std::memcpy(
|
||||
seq_ + size_, p, needed());
|
||||
size_ = length();
|
||||
return true;
|
||||
}
|
||||
if(BOOST_JSON_LIKELY(remain > 0))
|
||||
{
|
||||
std::memcpy(seq_ + size_, p, remain);
|
||||
size_ += static_cast<uint8_t>(remain);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char*
|
||||
data() const noexcept
|
||||
{
|
||||
return seq_;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
needed() const noexcept
|
||||
{
|
||||
return length() - size_;
|
||||
}
|
||||
|
||||
bool
|
||||
valid() const noexcept
|
||||
{
|
||||
BOOST_ASSERT(size_ >= length());
|
||||
return is_valid_utf8(seq_, first_);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_VALUE_HPP
|
||||
#define BOOST_JSON_DETAIL_VALUE_HPP
|
||||
|
||||
#include <boost/json/kind.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
struct key_t
|
||||
{
|
||||
};
|
||||
|
||||
#if 0
|
||||
template<class T>
|
||||
struct to_number_limit
|
||||
: std::numeric_limits<T>
|
||||
{
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct to_number_limit<T const>
|
||||
: to_number_limit<T>
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_number_limit<long long>
|
||||
{
|
||||
static constexpr long long (min)() noexcept
|
||||
{
|
||||
return -9223372036854774784;
|
||||
}
|
||||
|
||||
static constexpr long long (max)() noexcept
|
||||
{
|
||||
return 9223372036854774784;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_number_limit<unsigned long long>
|
||||
{
|
||||
static constexpr
|
||||
unsigned long long (min)() noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr
|
||||
unsigned long long (max)() noexcept
|
||||
{
|
||||
return 18446744073709549568ULL;
|
||||
}
|
||||
};
|
||||
#else
|
||||
|
||||
template<class T>
|
||||
class to_number_limit
|
||||
{
|
||||
// unsigned
|
||||
|
||||
static constexpr
|
||||
double min1(std::false_type)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double max1(std::false_type)
|
||||
{
|
||||
return max2u(std::integral_constant<
|
||||
bool, (std::numeric_limits<T>::max)() ==
|
||||
UINT64_MAX>{});
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double max2u(std::false_type)
|
||||
{
|
||||
return static_cast<double>(
|
||||
(std::numeric_limits<T>::max)());
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double max2u(std::true_type)
|
||||
{
|
||||
return 18446744073709549568.0;
|
||||
}
|
||||
|
||||
// signed
|
||||
|
||||
static constexpr
|
||||
double min1(std::true_type)
|
||||
{
|
||||
return min2s(std::integral_constant<
|
||||
bool, (std::numeric_limits<T>::max)() ==
|
||||
INT64_MAX>{});
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double min2s(std::false_type)
|
||||
{
|
||||
return static_cast<double>(
|
||||
(std::numeric_limits<T>::min)());
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double min2s(std::true_type)
|
||||
{
|
||||
return -9223372036854774784.0;
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double max1(std::true_type)
|
||||
{
|
||||
return max2s(std::integral_constant<
|
||||
bool, (std::numeric_limits<T>::max)() ==
|
||||
INT64_MAX>{});
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double max2s(std::false_type)
|
||||
{
|
||||
return static_cast<double>(
|
||||
(std::numeric_limits<T>::max)());
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double max2s(std::true_type)
|
||||
{
|
||||
return 9223372036854774784.0;
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr
|
||||
double (min)() noexcept
|
||||
{
|
||||
return min1(std::is_signed<T>{});
|
||||
}
|
||||
|
||||
static constexpr
|
||||
double (max)() noexcept
|
||||
{
|
||||
return max1(std::is_signed<T>{});
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct scalar
|
||||
{
|
||||
storage_ptr sp; // must come first
|
||||
kind k; // must come second
|
||||
union
|
||||
{
|
||||
bool b;
|
||||
std::int64_t i;
|
||||
std::uint64_t u;
|
||||
double d;
|
||||
};
|
||||
|
||||
explicit
|
||||
scalar(storage_ptr sp_ = {}) noexcept
|
||||
: sp(std::move(sp_))
|
||||
, k(json::kind::null)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
scalar(bool b_,
|
||||
storage_ptr sp_ = {}) noexcept
|
||||
: sp(std::move(sp_))
|
||||
, k(json::kind::bool_)
|
||||
, b(b_)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
scalar(std::int64_t i_,
|
||||
storage_ptr sp_ = {}) noexcept
|
||||
: sp(std::move(sp_))
|
||||
, k(json::kind::int64)
|
||||
, i(i_)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
scalar(std::uint64_t u_,
|
||||
storage_ptr sp_ = {}) noexcept
|
||||
: sp(std::move(sp_))
|
||||
, k(json::kind::uint64)
|
||||
, u(u_)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
scalar(double d_,
|
||||
storage_ptr sp_ = {}) noexcept
|
||||
: sp(std::move(sp_))
|
||||
, k(json::kind::double_)
|
||||
, d(d_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct access
|
||||
{
|
||||
template<class Value, class... Args>
|
||||
static
|
||||
Value&
|
||||
construct_value(Value* p, Args&&... args)
|
||||
{
|
||||
return *reinterpret_cast<
|
||||
Value*>(::new(p) Value(
|
||||
std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<class KeyValuePair, class... Args>
|
||||
static
|
||||
KeyValuePair&
|
||||
construct_key_value_pair(
|
||||
KeyValuePair* p, Args&&... args)
|
||||
{
|
||||
return *reinterpret_cast<
|
||||
KeyValuePair*>(::new(p)
|
||||
KeyValuePair(
|
||||
std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<class Value>
|
||||
static
|
||||
char const*
|
||||
release_key(
|
||||
Value& jv,
|
||||
std::size_t& len) noexcept
|
||||
{
|
||||
BOOST_ASSERT(jv.is_string());
|
||||
jv.str_.sp_.~storage_ptr();
|
||||
return jv.str_.impl_.release_key(len);
|
||||
}
|
||||
|
||||
using index_t = std::uint32_t;
|
||||
|
||||
template<class KeyValuePair>
|
||||
static
|
||||
index_t&
|
||||
next(KeyValuePair& e) noexcept
|
||||
{
|
||||
return e.next_;
|
||||
}
|
||||
|
||||
template<class KeyValuePair>
|
||||
static
|
||||
index_t const&
|
||||
next(KeyValuePair const& e) noexcept
|
||||
{
|
||||
return e.next_;
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
hash_value_impl( value const& jv ) noexcept;
|
||||
|
||||
} // detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+278
@@ -0,0 +1,278 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
|
||||
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
|
||||
#define BOOST_JSON_DETAIL_VALUE_FROM_HPP
|
||||
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/describe/enum_to_string.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
# include <optional>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template< class Ctx, class T >
|
||||
struct append_tuple_element {
|
||||
array& arr;
|
||||
Ctx const& ctx;
|
||||
T&& t;
|
||||
|
||||
template<std::size_t I>
|
||||
void
|
||||
operator()(mp11::mp_size_t<I>) const
|
||||
{
|
||||
using std::get;
|
||||
arr.emplace_back(value_from(
|
||||
get<I>(std::forward<T>(t)), ctx, arr.storage() ));
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
// User-provided conversion
|
||||
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( user_conversion_tag, value& jv, T&& from, Ctx const& )
|
||||
{
|
||||
tag_invoke( value_from_tag(), jv, static_cast<T&&>(from) );
|
||||
}
|
||||
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
|
||||
{
|
||||
using Sup = supported_context<Ctx, T, value_from_conversion>;
|
||||
tag_invoke( value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx) );
|
||||
}
|
||||
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl(
|
||||
full_context_conversion_tag, value& jv, T&& from, Ctx const& ctx)
|
||||
{
|
||||
using Sup = supported_context<Ctx, T, value_from_conversion>;
|
||||
tag_invoke(
|
||||
value_from_tag(), jv, static_cast<T&&>(from), Sup::get(ctx), ctx );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// Native conversion
|
||||
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( native_conversion_tag, value& jv, T&& from, Ctx const& )
|
||||
{
|
||||
jv = std::forward<T>(from);
|
||||
}
|
||||
|
||||
// null-like types
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( null_like_conversion_tag, value& jv, T&&, Ctx const& )
|
||||
{
|
||||
// do nothing
|
||||
BOOST_ASSERT(jv.is_null());
|
||||
(void)jv;
|
||||
}
|
||||
|
||||
// string-like types
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( string_like_conversion_tag, value& jv, T&& from, Ctx const& )
|
||||
{
|
||||
auto sv = static_cast<string_view>(from);
|
||||
jv.emplace_string().assign(sv);
|
||||
}
|
||||
|
||||
// map-like types
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( map_like_conversion_tag, value& jv, T&& from, Ctx const& ctx )
|
||||
{
|
||||
using std::get;
|
||||
object& obj = jv.emplace_object();
|
||||
obj.reserve(detail::try_size(from, size_implementation<T>()));
|
||||
for (auto&& elem : from)
|
||||
obj.emplace(
|
||||
get<0>(elem),
|
||||
value_from( get<1>(elem), ctx, obj.storage() ));
|
||||
}
|
||||
|
||||
// ranges
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( sequence_conversion_tag, value& jv, T&& from, Ctx const& ctx )
|
||||
{
|
||||
array& result = jv.emplace_array();
|
||||
result.reserve(detail::try_size(from, size_implementation<T>()));
|
||||
using ForwardedValue = forwarded_value<T&&>;
|
||||
for (auto&& elem : from)
|
||||
result.emplace_back(
|
||||
value_from(
|
||||
// not a static_cast in order to appease clang < 4.0
|
||||
ForwardedValue(elem),
|
||||
ctx,
|
||||
result.storage() ));
|
||||
}
|
||||
|
||||
// tuple-like types
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( tuple_conversion_tag, value& jv, T&& from, Ctx const& ctx )
|
||||
{
|
||||
constexpr std::size_t n =
|
||||
std::tuple_size<remove_cvref<T>>::value;
|
||||
array& arr = jv.emplace_array();
|
||||
arr.reserve(n);
|
||||
mp11::mp_for_each<mp11::mp_iota_c<n>>(
|
||||
append_tuple_element< Ctx, T >{ arr, ctx, std::forward<T>(from) });
|
||||
}
|
||||
|
||||
// no suitable conversion implementation
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl( no_conversion_tag, value&, T&&, Ctx const& )
|
||||
{
|
||||
static_assert(
|
||||
!std::is_same<T, T>::value,
|
||||
"No suitable tag_invoke overload found for the type");
|
||||
}
|
||||
|
||||
template< class Ctx, class T >
|
||||
struct from_described_member
|
||||
{
|
||||
using Ds = describe::describe_members<
|
||||
remove_cvref<T>, describe::mod_public | describe::mod_inherited>;
|
||||
|
||||
object& obj;
|
||||
Ctx const& ctx;
|
||||
T&& from;
|
||||
|
||||
template< class I >
|
||||
void
|
||||
operator()(I) const
|
||||
{
|
||||
using D = mp11::mp_at<Ds, I>;
|
||||
obj.emplace(
|
||||
D::name,
|
||||
value_from(
|
||||
static_cast<T&&>(from).* D::pointer,
|
||||
ctx,
|
||||
obj.storage()));
|
||||
}
|
||||
};
|
||||
|
||||
// described classes
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl(
|
||||
described_class_conversion_tag, value& jv, T&& from, Ctx const& ctx )
|
||||
{
|
||||
object& obj = jv.emplace_object();
|
||||
from_described_member<Ctx, T> member_converter{
|
||||
obj, ctx, static_cast<T&&>(from)};
|
||||
|
||||
using Ds = typename decltype(member_converter)::Ds;
|
||||
constexpr std::size_t N = mp11::mp_size<Ds>::value;
|
||||
obj.reserve(N);
|
||||
mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
|
||||
}
|
||||
|
||||
// described enums
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl(
|
||||
described_enum_conversion_tag, value& jv, T from, Ctx const& )
|
||||
{
|
||||
(void)jv;
|
||||
(void)from;
|
||||
#ifdef BOOST_DESCRIBE_CXX14
|
||||
char const* const name = describe::enum_to_string(from, nullptr);
|
||||
if( name )
|
||||
{
|
||||
string& str = jv.emplace_string();
|
||||
str.assign(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
using Integer = typename std::underlying_type< remove_cvref<T> >::type;
|
||||
jv = static_cast<Integer>(from);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// optionals
|
||||
template< class T, class Ctx >
|
||||
void
|
||||
value_from_impl(
|
||||
optional_conversion_tag, value& jv, T&& from, Ctx const& ctx )
|
||||
{
|
||||
if( from )
|
||||
value_from( *from, ctx, jv );
|
||||
else
|
||||
jv = nullptr;
|
||||
}
|
||||
|
||||
// variants
|
||||
template< class Ctx >
|
||||
struct value_from_visitor
|
||||
{
|
||||
value& jv;
|
||||
Ctx const& ctx;
|
||||
|
||||
template<class T>
|
||||
void
|
||||
operator()(T&& t)
|
||||
{
|
||||
value_from( static_cast<T&&>(t), ctx, jv );
|
||||
}
|
||||
};
|
||||
|
||||
template< class Ctx, class T >
|
||||
void
|
||||
value_from_impl( variant_conversion_tag, value& jv, T&& from, Ctx const& ctx )
|
||||
{
|
||||
visit( value_from_visitor<Ctx>{ jv, ctx }, static_cast<T&&>(from) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// Contextual conversions
|
||||
|
||||
template< class Ctx, class T >
|
||||
using value_from_category = conversion_category<
|
||||
Ctx, T, value_from_conversion >;
|
||||
|
||||
} // detail
|
||||
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
inline
|
||||
void
|
||||
tag_invoke(
|
||||
value_from_tag,
|
||||
value& jv,
|
||||
std::nullopt_t)
|
||||
{
|
||||
// do nothing
|
||||
BOOST_ASSERT(jv.is_null());
|
||||
(void)jv;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+883
@@ -0,0 +1,883 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
|
||||
// Copyright (c) 2021 Dmitry Arkhipov (grisumbras@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DETAIL_VALUE_TO_HPP
|
||||
#define BOOST_JSON_DETAIL_VALUE_TO_HPP
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/describe/enum_from_string.hpp>
|
||||
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
# include <optional>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
using has_reserve_member_helper = decltype(std::declval<T&>().reserve(0));
|
||||
template<class T>
|
||||
using has_reserve_member = mp11::mp_valid<has_reserve_member_helper, T>;
|
||||
template<class T>
|
||||
using reserve_implementation = mp11::mp_cond<
|
||||
is_tuple_like<T>, mp11::mp_int<2>,
|
||||
has_reserve_member<T>, mp11::mp_int<1>,
|
||||
mp11::mp_true, mp11::mp_int<0>>;
|
||||
|
||||
template<class T>
|
||||
error
|
||||
try_reserve(
|
||||
T&,
|
||||
std::size_t size,
|
||||
mp11::mp_int<2>)
|
||||
{
|
||||
constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
|
||||
if ( N != size )
|
||||
return error::size_mismatch;
|
||||
return error();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
error
|
||||
try_reserve(
|
||||
T& cont,
|
||||
std::size_t size,
|
||||
mp11::mp_int<1>)
|
||||
{
|
||||
cont.reserve(size);
|
||||
return error();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
error
|
||||
try_reserve(
|
||||
T&,
|
||||
std::size_t,
|
||||
mp11::mp_int<0>)
|
||||
{
|
||||
return error();
|
||||
}
|
||||
|
||||
|
||||
// identity conversion
|
||||
template< class Ctx >
|
||||
result<value>
|
||||
value_to_impl(
|
||||
value_conversion_tag,
|
||||
try_value_to_tag<value>,
|
||||
value const& jv,
|
||||
Ctx const& )
|
||||
{
|
||||
return jv;
|
||||
}
|
||||
|
||||
template< class Ctx >
|
||||
value
|
||||
value_to_impl(
|
||||
value_conversion_tag, value_to_tag<value>, value const& jv, Ctx const& )
|
||||
{
|
||||
return jv;
|
||||
}
|
||||
|
||||
// object
|
||||
template< class Ctx >
|
||||
result<object>
|
||||
value_to_impl(
|
||||
object_conversion_tag,
|
||||
try_value_to_tag<object>,
|
||||
value const& jv,
|
||||
Ctx const& )
|
||||
{
|
||||
object const* obj = jv.if_object();
|
||||
if( obj )
|
||||
return *obj;
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_object);
|
||||
return ec;
|
||||
}
|
||||
|
||||
// array
|
||||
template< class Ctx >
|
||||
result<array>
|
||||
value_to_impl(
|
||||
array_conversion_tag,
|
||||
try_value_to_tag<array>,
|
||||
value const& jv,
|
||||
Ctx const& )
|
||||
{
|
||||
array const* arr = jv.if_array();
|
||||
if( arr )
|
||||
return *arr;
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_array);
|
||||
return ec;
|
||||
}
|
||||
|
||||
// string
|
||||
template< class Ctx >
|
||||
result<string>
|
||||
value_to_impl(
|
||||
string_conversion_tag,
|
||||
try_value_to_tag<string>,
|
||||
value const& jv,
|
||||
Ctx const& )
|
||||
{
|
||||
string const* str = jv.if_string();
|
||||
if( str )
|
||||
return *str;
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_string);
|
||||
return ec;
|
||||
}
|
||||
|
||||
// bool
|
||||
template< class Ctx >
|
||||
result<bool>
|
||||
value_to_impl(
|
||||
bool_conversion_tag, try_value_to_tag<bool>, value const& jv, Ctx const& )
|
||||
{
|
||||
auto b = jv.if_bool();
|
||||
if( b )
|
||||
return *b;
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_bool);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
// integral and floating point
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
number_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = jv.to_number<T>(ec);
|
||||
if( ec.failed() )
|
||||
return {boost::system::in_place_error, ec};
|
||||
return {boost::system::in_place_value, n};
|
||||
}
|
||||
|
||||
// null-like conversion
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
null_like_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& )
|
||||
{
|
||||
if( jv.is_null() )
|
||||
return {boost::system::in_place_value, T{}};
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_null);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
// string-like types
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
string_like_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& )
|
||||
{
|
||||
auto str = jv.if_string();
|
||||
if( str )
|
||||
return {boost::system::in_place_value, T(str->subview())};
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_string);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
// map-like containers
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
map_like_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
object const* obj = jv.if_object();
|
||||
if( !obj )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_object);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
T res;
|
||||
error const e = detail::try_reserve(
|
||||
res, obj->size(), reserve_implementation<T>());
|
||||
if( e != error() )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL( ec, e );
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
auto ins = detail::inserter(res, inserter_implementation<T>());
|
||||
for( key_value_pair const& kv: *obj )
|
||||
{
|
||||
auto elem_res = try_value_to<mapped_type<T>>( kv.value(), ctx );
|
||||
if( elem_res.has_error() )
|
||||
return {boost::system::in_place_error, elem_res.error()};
|
||||
*ins++ = value_type<T>{
|
||||
key_type<T>(kv.key()),
|
||||
std::move(*elem_res)};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// all other containers
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
sequence_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
array const* arr = jv.if_array();
|
||||
if( !arr )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_array);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
T result;
|
||||
error const e = detail::try_reserve(
|
||||
result, arr->size(), reserve_implementation<T>());
|
||||
if( e != error() )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL( ec, e );
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
auto ins = detail::inserter(result, inserter_implementation<T>());
|
||||
for( value const& val: *arr )
|
||||
{
|
||||
auto elem_res = try_value_to<value_type<T>>( val, ctx );
|
||||
if( elem_res.has_error() )
|
||||
return {boost::system::in_place_error, elem_res.error()};
|
||||
*ins++ = std::move(*elem_res);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// tuple-like types
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
try_make_tuple_elem(value const& jv, Ctx const& ctx, error_code& ec)
|
||||
{
|
||||
if( ec.failed() )
|
||||
return {boost::system::in_place_error, ec};
|
||||
|
||||
auto result = try_value_to<T>( jv, ctx );
|
||||
ec = result.error();
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class Ctx, std::size_t... Is>
|
||||
result<T>
|
||||
try_make_tuple_like(
|
||||
array const& arr, Ctx const& ctx, boost::mp11::index_sequence<Is...>)
|
||||
{
|
||||
error_code ec;
|
||||
auto items = std::make_tuple(
|
||||
try_make_tuple_elem<
|
||||
typename std::decay<tuple_element_t<Is, T>>::type >(
|
||||
arr[Is], ctx, ec)
|
||||
...);
|
||||
if( ec.failed() )
|
||||
return {boost::system::in_place_error, ec};
|
||||
|
||||
return {
|
||||
boost::system::in_place_value, T(std::move(*std::get<Is>(items))...)};
|
||||
}
|
||||
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
tuple_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
error_code ec;
|
||||
|
||||
array const* arr = jv.if_array();
|
||||
if( !arr )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::not_array);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
constexpr std::size_t N = std::tuple_size<remove_cvref<T>>::value;
|
||||
if( N != arr->size() )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::size_mismatch);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
|
||||
return try_make_tuple_like<T>(
|
||||
*arr, ctx, boost::mp11::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template< class Ctx, class T, bool non_throwing = true >
|
||||
struct to_described_member
|
||||
{
|
||||
using Ds = describe::describe_members<
|
||||
T, describe::mod_public | describe::mod_inherited>;
|
||||
|
||||
using result_type = mp11::mp_eval_if_c< !non_throwing, T, result, T >;
|
||||
|
||||
result_type& res;
|
||||
object const& obj;
|
||||
std::size_t count;
|
||||
Ctx const& ctx;
|
||||
|
||||
template< class I >
|
||||
void
|
||||
operator()(I)
|
||||
{
|
||||
if( !res )
|
||||
return;
|
||||
|
||||
using D = mp11::mp_at<Ds, I>;
|
||||
using M = described_member_t<T, D>;
|
||||
|
||||
auto const found = obj.find(D::name);
|
||||
if( found == obj.end() )
|
||||
{
|
||||
BOOST_IF_CONSTEXPR( !is_optional_like<M>::value )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::unknown_name);
|
||||
res = {boost::system::in_place_error, ec};
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wunused"
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
auto member_res = try_value_to<M>( found->value(), ctx );
|
||||
#if defined(__GNUC__) && BOOST_GCC_VERSION >= 80000 && BOOST_GCC_VERSION < 11000
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
if( member_res )
|
||||
{
|
||||
(*res).* D::pointer = std::move(*member_res);
|
||||
++count;
|
||||
}
|
||||
else
|
||||
res = {boost::system::in_place_error, member_res.error()};
|
||||
}
|
||||
};
|
||||
|
||||
// described classes
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
described_class_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
result<T> res;
|
||||
|
||||
auto* obj = jv.if_object();
|
||||
if( !obj )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_object);
|
||||
res = {boost::system::in_place_error, ec};
|
||||
return res;
|
||||
}
|
||||
|
||||
to_described_member< Ctx, T > member_converter{ res, *obj, 0u, ctx };
|
||||
|
||||
using Ds = typename decltype(member_converter)::Ds;
|
||||
constexpr std::size_t N = mp11::mp_size<Ds>::value;
|
||||
mp11::mp_for_each< mp11::mp_iota_c<N> >(member_converter);
|
||||
|
||||
if( !res )
|
||||
return res;
|
||||
|
||||
if( member_converter.count != obj->size() )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::size_mismatch);
|
||||
res = {boost::system::in_place_error, ec};
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// described enums
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
described_enum_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& )
|
||||
{
|
||||
T val = {};
|
||||
(void)jv;
|
||||
#ifdef BOOST_DESCRIBE_CXX14
|
||||
error_code ec;
|
||||
|
||||
auto str = jv.if_string();
|
||||
if( !str )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::not_string);
|
||||
return {system::in_place_error, ec};
|
||||
}
|
||||
|
||||
if( !describe::enum_from_string(str->data(), val) )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::unknown_name);
|
||||
return {system::in_place_error, ec};
|
||||
}
|
||||
#endif
|
||||
|
||||
return {system::in_place_value, val};
|
||||
}
|
||||
|
||||
// optionals
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
optional_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx)
|
||||
{
|
||||
using Inner = value_result_type<T>;
|
||||
if( jv.is_null() )
|
||||
return {};
|
||||
else
|
||||
return try_value_to<Inner>(jv, ctx);
|
||||
}
|
||||
|
||||
// variants
|
||||
template< class T, class V, class I >
|
||||
using variant_construction_category = mp11::mp_cond<
|
||||
std::is_constructible< T, variant2::in_place_index_t<I::value>, V >,
|
||||
mp11::mp_int<2>,
|
||||
#ifndef BOOST_NO_CXX17_HDR_VARIANT
|
||||
std::is_constructible< T, std::in_place_index_t<I::value>, V >,
|
||||
mp11::mp_int<1>,
|
||||
#endif // BOOST_NO_CXX17_HDR_VARIANT
|
||||
mp11::mp_true,
|
||||
mp11::mp_int<0> >;
|
||||
|
||||
template< class T, class I, class V >
|
||||
T
|
||||
initialize_variant( V&& v, mp11::mp_int<0> )
|
||||
{
|
||||
T t;
|
||||
t.template emplace<I::value>( std::move(v) );
|
||||
return t;
|
||||
}
|
||||
|
||||
template< class T, class I, class V >
|
||||
T
|
||||
initialize_variant( V&& v, mp11::mp_int<2> )
|
||||
{
|
||||
return T( variant2::in_place_index_t<I::value>(), std::move(v) );
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX17_HDR_VARIANT
|
||||
template< class T, class I, class V >
|
||||
T
|
||||
initialize_variant( V&& v, mp11::mp_int<1> )
|
||||
{
|
||||
return T( std::in_place_index_t<I::value>(), std::move(v) );
|
||||
}
|
||||
#endif // BOOST_NO_CXX17_HDR_VARIANT
|
||||
|
||||
template< class T, class Ctx >
|
||||
struct alternative_converter
|
||||
{
|
||||
result<T>& res;
|
||||
value const& jv;
|
||||
Ctx const& ctx;
|
||||
|
||||
template< class I >
|
||||
void operator()( I ) const
|
||||
{
|
||||
if( res )
|
||||
return;
|
||||
|
||||
using V = mp11::mp_at<T, I>;
|
||||
auto attempt = try_value_to<V>(jv, ctx);
|
||||
if( attempt )
|
||||
{
|
||||
using cat = variant_construction_category<T, V, I>;
|
||||
res = initialize_variant<T, I>( std::move(*attempt), cat() );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template< class T, class Ctx >
|
||||
result<T>
|
||||
value_to_impl(
|
||||
variant_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx)
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::exhausted_variants);
|
||||
|
||||
using Is = mp11::mp_iota< mp11::mp_size<T> >;
|
||||
|
||||
result<T> res = {system::in_place_error, ec};
|
||||
mp11::mp_for_each<Is>( alternative_converter<T, Ctx>{res, jv, ctx} );
|
||||
return res;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// User-provided conversions; throwing -> throwing
|
||||
template< class T, class Ctx >
|
||||
mp11::mp_if< mp11::mp_valid<has_user_conversion_to_impl, T>, T >
|
||||
value_to_impl(
|
||||
user_conversion_tag, value_to_tag<T> tag, value const& jv, Ctx const&)
|
||||
{
|
||||
return tag_invoke(tag, jv);
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if<
|
||||
mp11::mp_valid< has_context_conversion_to_impl, typename Sup::type, T>, T >
|
||||
value_to_impl(
|
||||
context_conversion_tag,
|
||||
value_to_tag<T> tag,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
return tag_invoke( tag, jv, Sup::get(ctx) );
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if<
|
||||
mp11::mp_valid<
|
||||
has_full_context_conversion_to_impl, typename Sup::type, T>,
|
||||
T>
|
||||
value_to_impl(
|
||||
full_context_conversion_tag,
|
||||
value_to_tag<T> tag,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
return tag_invoke( tag, jv, Sup::get(ctx), ctx );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// User-provided conversions; throwing -> nonthrowing
|
||||
template< class T, class Ctx >
|
||||
mp11::mp_if_c< !mp11::mp_valid<has_user_conversion_to_impl, T>::value, T>
|
||||
value_to_impl(
|
||||
user_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& )
|
||||
{
|
||||
auto res = tag_invoke(try_value_to_tag<T>(), jv);
|
||||
if( res.has_error() )
|
||||
throw_system_error( res.error() );
|
||||
return std::move(*res);
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if_c<
|
||||
!mp11::mp_valid<
|
||||
has_context_conversion_to_impl, typename Sup::type, T>::value,
|
||||
T>
|
||||
value_to_impl(
|
||||
context_conversion_tag, value_to_tag<T>, value const& jv, Ctx const& ctx )
|
||||
{
|
||||
auto res = tag_invoke( try_value_to_tag<T>(), jv, Sup::get(ctx) );
|
||||
if( res.has_error() )
|
||||
throw_system_error( res.error() );
|
||||
return std::move(*res);
|
||||
}
|
||||
|
||||
template< class Ctx >
|
||||
std::tuple<allow_exceptions, Ctx>
|
||||
make_throwing_context(Ctx const& ctx)
|
||||
{
|
||||
return std::tuple<allow_exceptions, Ctx>(allow_exceptions(), ctx);
|
||||
}
|
||||
|
||||
template< class... Ctxes >
|
||||
std::tuple<allow_exceptions, Ctxes...>
|
||||
make_throwing_context(std::tuple<Ctxes...> const& ctx)
|
||||
{
|
||||
return std::tuple_cat(std::make_tuple( allow_exceptions() ), ctx);
|
||||
}
|
||||
|
||||
template< class... Ctxes >
|
||||
std::tuple<allow_exceptions, Ctxes...> const&
|
||||
make_throwing_context(std::tuple<allow_exceptions, Ctxes...> const& ctx)
|
||||
noexcept
|
||||
{
|
||||
return ctx;
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if_c<
|
||||
!mp11::mp_valid<
|
||||
has_full_context_conversion_to_impl, typename Sup::type, T>::value,
|
||||
T>
|
||||
value_to_impl(
|
||||
full_context_conversion_tag,
|
||||
value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
auto res = tag_invoke(
|
||||
try_value_to_tag<T>(),
|
||||
jv,
|
||||
Sup::get(ctx),
|
||||
make_throwing_context(ctx));
|
||||
if( res.has_error() )
|
||||
throw_system_error( res.error() );
|
||||
return std::move(*res);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// User-provided conversions; nonthrowing -> nonthrowing
|
||||
template< class T, class Ctx >
|
||||
mp11::mp_if<
|
||||
mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>, result<T> >
|
||||
value_to_impl(
|
||||
user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
|
||||
{
|
||||
return tag_invoke(try_value_to_tag<T>(), jv);
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if<
|
||||
mp11::mp_valid<
|
||||
has_nonthrowing_context_conversion_to_impl, typename Sup::type, T>,
|
||||
result<T> >
|
||||
value_to_impl(
|
||||
context_conversion_tag,
|
||||
try_value_to_tag<T> tag,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
return tag_invoke( tag, jv, Sup::get(ctx) );
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if<
|
||||
mp11::mp_valid<
|
||||
has_nonthrowing_full_context_conversion_to_impl,
|
||||
typename Sup::type,
|
||||
T>,
|
||||
result<T> >
|
||||
value_to_impl(
|
||||
full_context_conversion_tag,
|
||||
try_value_to_tag<T> tag,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
return tag_invoke( tag, jv, Sup::get(ctx), ctx );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// User-provided conversions; nonthrowing -> throwing
|
||||
|
||||
template< class Ctx >
|
||||
struct does_allow_exceptions : std::false_type
|
||||
{ };
|
||||
|
||||
template< class... Ctxes >
|
||||
struct does_allow_exceptions< std::tuple<allow_exceptions, Ctxes...> >
|
||||
: std::true_type
|
||||
{ };
|
||||
|
||||
template< class T, class... Args >
|
||||
result<T>
|
||||
wrap_conversion_exceptions( std::true_type, value_to_tag<T>, Args&& ... args )
|
||||
{
|
||||
return {
|
||||
boost::system::in_place_value,
|
||||
tag_invoke( value_to_tag<T>(), static_cast<Args&&>(args)... )};
|
||||
}
|
||||
|
||||
template< class T, class... Args >
|
||||
result<T>
|
||||
wrap_conversion_exceptions( std::false_type, value_to_tag<T>, Args&& ... args )
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
return wrap_conversion_exceptions(
|
||||
std::true_type(),
|
||||
value_to_tag<T>(),
|
||||
static_cast<Args&&>(args)... );
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch( std::bad_alloc const&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch( system_error const& e)
|
||||
{
|
||||
return {boost::system::in_place_error, e.code()};
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::exception);
|
||||
return {boost::system::in_place_error, ec};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template< class T, class Ctx >
|
||||
mp11::mp_if_c<
|
||||
!mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>::value,
|
||||
result<T> >
|
||||
value_to_impl(
|
||||
user_conversion_tag, try_value_to_tag<T>, value const& jv, Ctx const& )
|
||||
{
|
||||
return wrap_conversion_exceptions(
|
||||
does_allow_exceptions<Ctx>(), value_to_tag<T>(), jv);
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if_c<
|
||||
!mp11::mp_valid<
|
||||
has_nonthrowing_context_conversion_to_impl,
|
||||
typename Sup::type,
|
||||
T>::value,
|
||||
result<T> >
|
||||
value_to_impl(
|
||||
context_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
return wrap_conversion_exceptions(
|
||||
does_allow_exceptions<Ctx>(), value_to_tag<T>(), jv, Sup::get(ctx) );
|
||||
}
|
||||
|
||||
template<
|
||||
class T,
|
||||
class Ctx,
|
||||
class Sup = supported_context<Ctx, T, value_to_conversion>
|
||||
>
|
||||
mp11::mp_if_c<
|
||||
!mp11::mp_valid<
|
||||
has_nonthrowing_full_context_conversion_to_impl,
|
||||
typename Sup::type,
|
||||
T>::value,
|
||||
result<T> >
|
||||
value_to_impl(
|
||||
full_context_conversion_tag,
|
||||
try_value_to_tag<T>,
|
||||
value const& jv,
|
||||
Ctx const& ctx )
|
||||
{
|
||||
return wrap_conversion_exceptions(
|
||||
does_allow_exceptions<Ctx>(),
|
||||
value_to_tag<T>(),
|
||||
jv,
|
||||
Sup::get(ctx),
|
||||
ctx);
|
||||
}
|
||||
|
||||
// no suitable conversion implementation
|
||||
template< class T, class Ctx >
|
||||
T
|
||||
value_to_impl( no_conversion_tag, value_to_tag<T>, value const&, Ctx const& )
|
||||
{
|
||||
static_assert(
|
||||
!std::is_same<T, T>::value,
|
||||
"No suitable tag_invoke overload found for the type");
|
||||
}
|
||||
|
||||
// generic wrapper over non-throwing implementations
|
||||
template< class Impl, class T, class Ctx >
|
||||
T
|
||||
value_to_impl( Impl impl, value_to_tag<T>, value const& jv, Ctx const& ctx )
|
||||
{
|
||||
return value_to_impl(
|
||||
impl, try_value_to_tag<T>(), jv, make_throwing_context(ctx) ).value();
|
||||
}
|
||||
|
||||
template< class Ctx, class T >
|
||||
using value_to_category = conversion_category<
|
||||
Ctx, T, value_to_conversion >;
|
||||
|
||||
} // detail
|
||||
|
||||
#ifndef BOOST_NO_CXX17_HDR_OPTIONAL
|
||||
inline
|
||||
result<std::nullopt_t>
|
||||
tag_invoke(
|
||||
try_value_to_tag<std::nullopt_t>,
|
||||
value const& jv)
|
||||
{
|
||||
if( jv.is_null() )
|
||||
return std::nullopt;
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::not_null);
|
||||
return ec;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_ERROR_HPP
|
||||
#define BOOST_JSON_ERROR_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/system_error.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** Error codes returned by JSON operations
|
||||
|
||||
*/
|
||||
enum class error
|
||||
{
|
||||
//
|
||||
// parse errors
|
||||
//
|
||||
|
||||
/// syntax error
|
||||
syntax = 1,
|
||||
|
||||
/// extra data
|
||||
extra_data,
|
||||
|
||||
/// incomplete JSON
|
||||
incomplete,
|
||||
|
||||
/// exponent too large
|
||||
exponent_overflow,
|
||||
|
||||
/// too deep
|
||||
too_deep,
|
||||
|
||||
/// illegal leading surrogate
|
||||
illegal_leading_surrogate,
|
||||
|
||||
/// illegal trailing surrogate
|
||||
illegal_trailing_surrogate,
|
||||
|
||||
/// expected hex digit
|
||||
expected_hex_digit,
|
||||
|
||||
/// expected utf16 escape
|
||||
expected_utf16_escape,
|
||||
|
||||
/// An object contains too many elements
|
||||
object_too_large,
|
||||
|
||||
/// An array contains too many elements
|
||||
array_too_large,
|
||||
|
||||
/// A key is too large
|
||||
key_too_large,
|
||||
|
||||
/// A string is too large
|
||||
string_too_large,
|
||||
|
||||
/// A number is too large
|
||||
number_too_large,
|
||||
|
||||
/// error occured when trying to read input
|
||||
input_error,
|
||||
|
||||
//
|
||||
// generic errors
|
||||
//
|
||||
|
||||
/// An exception was thrown during operation
|
||||
exception,
|
||||
|
||||
/// A requested element is outside of container's range
|
||||
out_of_range,
|
||||
|
||||
/// test failure
|
||||
test_failure,
|
||||
|
||||
//
|
||||
// JSON Pointer errors
|
||||
//
|
||||
|
||||
/// missing slash character before token reference
|
||||
missing_slash,
|
||||
|
||||
/// invalid escape sequence
|
||||
invalid_escape,
|
||||
|
||||
/// token should be a number but cannot be parsed as such
|
||||
token_not_number,
|
||||
|
||||
/// current value is neither an object nor an array
|
||||
value_is_scalar,
|
||||
|
||||
/// current value does not contain referenced value
|
||||
not_found,
|
||||
|
||||
/// token cannot be represented by std::size_t
|
||||
token_overflow,
|
||||
|
||||
/// past-the-end index is not supported
|
||||
past_the_end,
|
||||
|
||||
//
|
||||
// Conversion errors
|
||||
//
|
||||
|
||||
/// JSON number was expected during conversion
|
||||
not_number,
|
||||
|
||||
/// number cast is not exact
|
||||
not_exact,
|
||||
|
||||
/// JSON null was expected during conversion
|
||||
not_null,
|
||||
|
||||
/// JSON bool was expected during conversion
|
||||
not_bool,
|
||||
|
||||
/// JSON array was expected during conversion
|
||||
not_array,
|
||||
|
||||
/// JSON object was expected during conversion
|
||||
not_object,
|
||||
|
||||
/// JSON string was expected during conversion
|
||||
not_string,
|
||||
|
||||
/// std::int64_t was expected during conversion
|
||||
not_int64,
|
||||
|
||||
/// std::uint64_t was expected during conversion
|
||||
not_uint64,
|
||||
|
||||
/// `double` was expected during conversion
|
||||
not_double,
|
||||
|
||||
/// JSON integer was expected during conversion
|
||||
not_integer,
|
||||
|
||||
/// source composite has size incompatible with target
|
||||
size_mismatch,
|
||||
|
||||
/// none of the possible conversions were successful
|
||||
exhausted_variants,
|
||||
|
||||
/// the key does not correspond to a known name
|
||||
unknown_name,
|
||||
};
|
||||
|
||||
/** Error conditions corresponding to JSON errors
|
||||
*/
|
||||
enum class condition
|
||||
{
|
||||
/// A parser-related error
|
||||
parse_error = 1,
|
||||
|
||||
/// An error related to parsing JSON pointer string
|
||||
pointer_parse_error,
|
||||
|
||||
/// An error related to applying JSON pointer string to a value
|
||||
pointer_use_error,
|
||||
|
||||
/// A conversion error
|
||||
conversion_error,
|
||||
|
||||
/// A generic error
|
||||
generic_error,
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/json/impl/error.hpp>
|
||||
|
||||
#endif
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_FWD_HPP
|
||||
#define BOOST_JSON_FWD_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
// Forward declarations
|
||||
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
|
||||
class array;
|
||||
class object;
|
||||
class string;
|
||||
class value;
|
||||
|
||||
class key_value_pair;
|
||||
class storage_ptr;
|
||||
|
||||
struct value_from_tag;
|
||||
|
||||
template<class T>
|
||||
struct value_to_tag;
|
||||
|
||||
template<class T>
|
||||
struct try_value_to_tag;
|
||||
|
||||
template<class T1, class T2>
|
||||
struct result_for;
|
||||
|
||||
template<class T>
|
||||
struct is_string_like;
|
||||
|
||||
template<class T>
|
||||
struct is_sequence_like;
|
||||
|
||||
template<class T>
|
||||
struct is_map_like;
|
||||
|
||||
template<class T>
|
||||
struct is_tuple_like;
|
||||
|
||||
template<class T>
|
||||
struct is_null_like;
|
||||
|
||||
template<class T>
|
||||
struct is_described_class;
|
||||
|
||||
template<class T>
|
||||
struct is_described_enum;
|
||||
|
||||
template<class T>
|
||||
void value_from( T&& t, value& jv );
|
||||
|
||||
template<class T, class Context>
|
||||
void value_from( T&& t, value& jv, Context const& ctx );
|
||||
|
||||
template<class T>
|
||||
T value_to( value const & v );
|
||||
|
||||
template<class T, class Context>
|
||||
T value_to( value const & v, Context const& ctx );
|
||||
|
||||
template<class T>
|
||||
typename result_for<T, value>::type
|
||||
try_value_to( value const & jv );
|
||||
|
||||
template<class T, class Context>
|
||||
typename result_for<T, value>::type
|
||||
try_value_to( value const & jv, Context const& ctx );
|
||||
|
||||
template<class T>
|
||||
typename result_for<T, value>::type
|
||||
result_from_errno( int e, boost::source_location const* loc ) noexcept;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+590
@@ -0,0 +1,590 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_ARRAY_HPP
|
||||
#define BOOST_JSON_IMPL_ARRAY_HPP
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
struct alignas(value)
|
||||
array::table
|
||||
{
|
||||
std::uint32_t size = 0;
|
||||
std::uint32_t capacity = 0;
|
||||
|
||||
constexpr table();
|
||||
|
||||
value&
|
||||
operator[](std::size_t pos) noexcept
|
||||
{
|
||||
return (reinterpret_cast<
|
||||
value*>(this + 1))[pos];
|
||||
}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
static
|
||||
table*
|
||||
allocate(
|
||||
std::size_t capacity,
|
||||
storage_ptr const& sp);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
static
|
||||
void
|
||||
deallocate(
|
||||
table* p,
|
||||
storage_ptr const& sp);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class array::revert_construct
|
||||
{
|
||||
array* arr_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
revert_construct(
|
||||
array& arr) noexcept
|
||||
: arr_(&arr)
|
||||
{
|
||||
}
|
||||
|
||||
~revert_construct()
|
||||
{
|
||||
if(! arr_)
|
||||
return;
|
||||
arr_->destroy();
|
||||
}
|
||||
|
||||
void
|
||||
commit() noexcept
|
||||
{
|
||||
arr_ = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class array::revert_insert
|
||||
{
|
||||
array* arr_;
|
||||
std::size_t const i_;
|
||||
std::size_t const n_;
|
||||
|
||||
public:
|
||||
value* p;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
revert_insert(
|
||||
const_iterator pos,
|
||||
std::size_t n,
|
||||
array& arr);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
~revert_insert();
|
||||
|
||||
value*
|
||||
commit() noexcept
|
||||
{
|
||||
auto it =
|
||||
arr_->data() + i_;
|
||||
arr_ = nullptr;
|
||||
return it;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
array::
|
||||
relocate(
|
||||
value* dest,
|
||||
value* src,
|
||||
std::size_t n) noexcept
|
||||
{
|
||||
if(n == 0)
|
||||
return;
|
||||
std::memmove(
|
||||
static_cast<void*>(dest),
|
||||
static_cast<void const*>(src),
|
||||
n * sizeof(value));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Construction
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class InputIt, class>
|
||||
array::
|
||||
array(
|
||||
InputIt first, InputIt last,
|
||||
storage_ptr sp)
|
||||
: array(
|
||||
first, last,
|
||||
std::move(sp),
|
||||
iter_cat<InputIt>{})
|
||||
{
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_constructible<value,
|
||||
decltype(*first)>::value);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Modifiers
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class InputIt, class>
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last) ->
|
||||
iterator
|
||||
{
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_constructible<value,
|
||||
decltype(*first)>::value);
|
||||
return insert(pos, first, last,
|
||||
iter_cat<InputIt>{});
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
auto
|
||||
array::
|
||||
emplace(
|
||||
const_iterator pos,
|
||||
Arg&& arg) ->
|
||||
iterator
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
pos >= begin() &&
|
||||
pos <= end());
|
||||
value jv(
|
||||
std::forward<Arg>(arg),
|
||||
storage());
|
||||
return insert(pos, pilfer(jv));
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
value&
|
||||
array::
|
||||
emplace_back(Arg&& arg)
|
||||
{
|
||||
value jv(
|
||||
std::forward<Arg>(arg),
|
||||
storage());
|
||||
return push_back(pilfer(jv));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Element access
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
value&
|
||||
array::
|
||||
at(std::size_t pos) &
|
||||
{
|
||||
auto const& self = *this;
|
||||
return const_cast< value& >( self.at(pos) );
|
||||
}
|
||||
|
||||
value&&
|
||||
array::
|
||||
at(std::size_t pos) &&
|
||||
{
|
||||
return std::move( at(pos) );
|
||||
}
|
||||
|
||||
value const&
|
||||
array::
|
||||
at(std::size_t pos) const&
|
||||
{
|
||||
if(pos >= t_->size)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::out_of_range, &loc );
|
||||
}
|
||||
return (*t_)[pos];
|
||||
}
|
||||
|
||||
value&
|
||||
array::
|
||||
operator[](std::size_t pos) & noexcept
|
||||
{
|
||||
BOOST_ASSERT(pos < t_->size);
|
||||
return (*t_)[pos];
|
||||
}
|
||||
|
||||
value&&
|
||||
array::
|
||||
operator[](std::size_t pos) && noexcept
|
||||
{
|
||||
return std::move( (*this)[pos] );
|
||||
}
|
||||
|
||||
value const&
|
||||
array::
|
||||
operator[](std::size_t pos) const& noexcept
|
||||
{
|
||||
BOOST_ASSERT(pos < t_->size);
|
||||
return (*t_)[pos];
|
||||
}
|
||||
|
||||
value&
|
||||
array::
|
||||
front() & noexcept
|
||||
{
|
||||
BOOST_ASSERT(t_->size > 0);
|
||||
return (*t_)[0];
|
||||
}
|
||||
|
||||
value&&
|
||||
array::
|
||||
front() && noexcept
|
||||
{
|
||||
return std::move( front() );
|
||||
}
|
||||
|
||||
value const&
|
||||
array::
|
||||
front() const& noexcept
|
||||
{
|
||||
BOOST_ASSERT(t_->size > 0);
|
||||
return (*t_)[0];
|
||||
}
|
||||
|
||||
value&
|
||||
array::
|
||||
back() & noexcept
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
t_->size > 0);
|
||||
return (*t_)[t_->size - 1];
|
||||
}
|
||||
|
||||
value&&
|
||||
array::
|
||||
back() && noexcept
|
||||
{
|
||||
return std::move( back() );
|
||||
}
|
||||
|
||||
value const&
|
||||
array::
|
||||
back() const& noexcept
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
t_->size > 0);
|
||||
return (*t_)[t_->size - 1];
|
||||
}
|
||||
|
||||
value*
|
||||
array::
|
||||
data() noexcept
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
value const*
|
||||
array::
|
||||
data() const noexcept
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
value const*
|
||||
array::
|
||||
if_contains(
|
||||
std::size_t pos) const noexcept
|
||||
{
|
||||
if( pos < t_->size )
|
||||
return &(*t_)[pos];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
value*
|
||||
array::
|
||||
if_contains(
|
||||
std::size_t pos) noexcept
|
||||
{
|
||||
if( pos < t_->size )
|
||||
return &(*t_)[pos];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Iterators
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
auto
|
||||
array::
|
||||
begin() noexcept ->
|
||||
iterator
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
begin() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
cbegin() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
end() noexcept ->
|
||||
iterator
|
||||
{
|
||||
return &(*t_)[t_->size];
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
end() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[t_->size];
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
cend() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[t_->size];
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
rbegin() noexcept ->
|
||||
reverse_iterator
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
rbegin() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
crbegin() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
rend() noexcept ->
|
||||
reverse_iterator
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
rend() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
crend() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Capacity
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
std::size_t
|
||||
array::
|
||||
size() const noexcept
|
||||
{
|
||||
return t_->size;
|
||||
}
|
||||
|
||||
constexpr
|
||||
std::size_t
|
||||
array::
|
||||
max_size() noexcept
|
||||
{
|
||||
// max_size depends on the address model
|
||||
using min = std::integral_constant<std::size_t,
|
||||
(std::size_t(-1) - sizeof(table)) / sizeof(value)>;
|
||||
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
|
||||
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
array::
|
||||
capacity() const noexcept
|
||||
{
|
||||
return t_->capacity;
|
||||
}
|
||||
|
||||
bool
|
||||
array::
|
||||
empty() const noexcept
|
||||
{
|
||||
return t_->size == 0;
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
reserve(
|
||||
std::size_t new_capacity)
|
||||
{
|
||||
// never shrink
|
||||
if(new_capacity <= t_->capacity)
|
||||
return;
|
||||
reserve_impl(new_capacity);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// private
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class InputIt>
|
||||
array::
|
||||
array(
|
||||
InputIt first, InputIt last,
|
||||
storage_ptr sp,
|
||||
std::input_iterator_tag)
|
||||
: sp_(std::move(sp))
|
||||
, t_(&empty_)
|
||||
{
|
||||
revert_construct r(*this);
|
||||
while(first != last)
|
||||
{
|
||||
reserve(size() + 1);
|
||||
::new(end()) value(
|
||||
*first++, sp_);
|
||||
++t_->size;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
array::
|
||||
array(
|
||||
InputIt first, InputIt last,
|
||||
storage_ptr sp,
|
||||
std::forward_iterator_tag)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
std::size_t n =
|
||||
std::distance(first, last);
|
||||
if( n == 0 )
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
|
||||
t_ = table::allocate(n, sp_);
|
||||
t_->size = 0;
|
||||
revert_construct r(*this);
|
||||
while(n--)
|
||||
{
|
||||
::new(end()) value(
|
||||
*first++, sp_);
|
||||
++t_->size;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last,
|
||||
std::input_iterator_tag) ->
|
||||
iterator
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
pos >= begin() && pos <= end());
|
||||
if(first == last)
|
||||
return data() + (pos - data());
|
||||
array temp(first, last, sp_);
|
||||
revert_insert r(
|
||||
pos, temp.size(), *this);
|
||||
relocate(
|
||||
r.p,
|
||||
temp.data(),
|
||||
temp.size());
|
||||
temp.t_->size = 0;
|
||||
return r.commit();
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
InputIt first, InputIt last,
|
||||
std::forward_iterator_tag) ->
|
||||
iterator
|
||||
{
|
||||
std::size_t n =
|
||||
std::distance(first, last);
|
||||
revert_insert r(pos, n, *this);
|
||||
while(n--)
|
||||
{
|
||||
::new(r.p) value(*first++);
|
||||
++r.p;
|
||||
}
|
||||
return r.commit();
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+776
@@ -0,0 +1,776 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_ARRAY_IPP
|
||||
#define BOOST_JSON_IMPL_ARRAY_IPP
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/pilfer.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
constexpr array::table::table() = default;
|
||||
|
||||
// empty arrays point here
|
||||
BOOST_JSON_REQUIRE_CONST_INIT
|
||||
array::table array::empty_;
|
||||
|
||||
auto
|
||||
array::
|
||||
table::
|
||||
allocate(
|
||||
std::size_t capacity,
|
||||
storage_ptr const& sp) ->
|
||||
table*
|
||||
{
|
||||
BOOST_ASSERT(capacity > 0);
|
||||
if(capacity > array::max_size())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::array_too_large, &loc );
|
||||
}
|
||||
auto p = reinterpret_cast<
|
||||
table*>(sp->allocate(
|
||||
sizeof(table) +
|
||||
capacity * sizeof(value),
|
||||
alignof(value)));
|
||||
p->capacity = static_cast<
|
||||
std::uint32_t>(capacity);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
table::
|
||||
deallocate(
|
||||
table* p,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
if(p->capacity == 0)
|
||||
return;
|
||||
sp->deallocate(p,
|
||||
sizeof(table) +
|
||||
p->capacity * sizeof(value),
|
||||
alignof(value));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
array::
|
||||
revert_insert::
|
||||
revert_insert(
|
||||
const_iterator pos,
|
||||
std::size_t n,
|
||||
array& arr)
|
||||
: arr_(&arr)
|
||||
, i_(pos - arr_->data())
|
||||
, n_(n)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
pos >= arr_->begin() &&
|
||||
pos <= arr_->end());
|
||||
if( n_ <= arr_->capacity() -
|
||||
arr_->size())
|
||||
{
|
||||
// fast path
|
||||
p = arr_->data() + i_;
|
||||
if(n_ == 0)
|
||||
return;
|
||||
relocate(
|
||||
p + n_,
|
||||
p,
|
||||
arr_->size() - i_);
|
||||
arr_->t_->size = static_cast<
|
||||
std::uint32_t>(
|
||||
arr_->t_->size + n_);
|
||||
return;
|
||||
}
|
||||
if(n_ > max_size() - arr_->size())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::array_too_large, &loc );
|
||||
}
|
||||
auto t = table::allocate(
|
||||
arr_->growth(arr_->size() + n_),
|
||||
arr_->sp_);
|
||||
t->size = static_cast<std::uint32_t>(
|
||||
arr_->size() + n_);
|
||||
p = &(*t)[0] + i_;
|
||||
relocate(
|
||||
&(*t)[0],
|
||||
arr_->data(),
|
||||
i_);
|
||||
relocate(
|
||||
&(*t)[i_ + n_],
|
||||
arr_->data() + i_,
|
||||
arr_->size() - i_);
|
||||
t = detail::exchange(arr_->t_, t);
|
||||
table::deallocate(t, arr_->sp_);
|
||||
}
|
||||
|
||||
array::
|
||||
revert_insert::
|
||||
~revert_insert()
|
||||
{
|
||||
if(! arr_)
|
||||
return;
|
||||
BOOST_ASSERT(n_ != 0);
|
||||
auto const pos =
|
||||
arr_->data() + i_;
|
||||
arr_->destroy(pos, p);
|
||||
arr_->t_->size = static_cast<
|
||||
std::uint32_t>(
|
||||
arr_->t_->size - n_);
|
||||
relocate(
|
||||
pos,
|
||||
pos + n_,
|
||||
arr_->size() - i_);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
array::
|
||||
destroy(
|
||||
value* first, value* last) noexcept
|
||||
{
|
||||
if(sp_.is_not_shared_and_deallocate_is_trivial())
|
||||
return;
|
||||
while(last-- != first)
|
||||
last->~value();
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
destroy() noexcept
|
||||
{
|
||||
if(sp_.is_not_shared_and_deallocate_is_trivial())
|
||||
return;
|
||||
auto last = end();
|
||||
auto const first = begin();
|
||||
while(last-- != first)
|
||||
last->~value();
|
||||
table::deallocate(t_, sp_);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Special Members
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
array::
|
||||
array(detail::unchecked_array&& ua)
|
||||
: sp_(ua.storage())
|
||||
{
|
||||
BOOST_STATIC_ASSERT(
|
||||
alignof(table) == alignof(value));
|
||||
if(ua.size() == 0)
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
t_= table::allocate(
|
||||
ua.size(), sp_);
|
||||
t_->size = static_cast<
|
||||
std::uint32_t>(ua.size());
|
||||
ua.relocate(data());
|
||||
}
|
||||
|
||||
array::
|
||||
~array() noexcept
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
std::size_t count,
|
||||
value const& v,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
if(count == 0)
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
t_= table::allocate(
|
||||
count, sp_);
|
||||
t_->size = 0;
|
||||
revert_construct r(*this);
|
||||
while(count--)
|
||||
{
|
||||
::new(end()) value(v, sp_);
|
||||
++t_->size;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
std::size_t count,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
if(count == 0)
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
t_ = table::allocate(
|
||||
count, sp_);
|
||||
t_->size = static_cast<
|
||||
std::uint32_t>(count);
|
||||
auto p = data();
|
||||
do
|
||||
{
|
||||
::new(p++) value(sp_);
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
|
||||
array::
|
||||
array(array const& other)
|
||||
: array(other, other.sp_)
|
||||
{
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
array const& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
if(other.empty())
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
t_ = table::allocate(
|
||||
other.size(), sp_);
|
||||
t_->size = 0;
|
||||
revert_construct r(*this);
|
||||
auto src = other.data();
|
||||
auto dest = data();
|
||||
auto const n = other.size();
|
||||
do
|
||||
{
|
||||
::new(dest++) value(
|
||||
*src++, sp_);
|
||||
++t_->size;
|
||||
}
|
||||
while(t_->size < n);
|
||||
r.commit();
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
array&& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
if(*sp_ == *other.sp_)
|
||||
{
|
||||
// same resource
|
||||
t_ = detail::exchange(
|
||||
other.t_, &empty_);
|
||||
return;
|
||||
}
|
||||
else if(other.empty())
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
// copy
|
||||
t_ = table::allocate(
|
||||
other.size(), sp_);
|
||||
t_->size = 0;
|
||||
revert_construct r(*this);
|
||||
auto src = other.data();
|
||||
auto dest = data();
|
||||
auto const n = other.size();
|
||||
do
|
||||
{
|
||||
::new(dest++) value(
|
||||
*src++, sp_);
|
||||
++t_->size;
|
||||
}
|
||||
while(t_->size < n);
|
||||
r.commit();
|
||||
}
|
||||
|
||||
array::
|
||||
array(
|
||||
std::initializer_list<
|
||||
value_ref> init,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
if(init.size() == 0)
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
t_ = table::allocate(
|
||||
init.size(), sp_);
|
||||
t_->size = 0;
|
||||
revert_construct r(*this);
|
||||
value_ref::write_array(
|
||||
data(), init, sp_);
|
||||
t_->size = static_cast<
|
||||
std::uint32_t>(init.size());
|
||||
r.commit();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
array&
|
||||
array::
|
||||
operator=(array const& other)
|
||||
{
|
||||
array(other,
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
array&
|
||||
array::
|
||||
operator=(array&& other)
|
||||
{
|
||||
array(std::move(other),
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
array&
|
||||
array::
|
||||
operator=(
|
||||
std::initializer_list<value_ref> init)
|
||||
{
|
||||
array(init,
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Capacity
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
array::
|
||||
shrink_to_fit() noexcept
|
||||
{
|
||||
if(capacity() <= size())
|
||||
return;
|
||||
if(size() == 0)
|
||||
{
|
||||
table::deallocate(t_, sp_);
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
auto t = table::allocate(
|
||||
size(), sp_);
|
||||
relocate(
|
||||
&(*t)[0],
|
||||
data(),
|
||||
size());
|
||||
t->size = static_cast<
|
||||
std::uint32_t>(size());
|
||||
t = detail::exchange(
|
||||
t_, t);
|
||||
table::deallocate(t, sp_);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// eat the exception
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Modifiers
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
array::
|
||||
clear() noexcept
|
||||
{
|
||||
if(size() == 0)
|
||||
return;
|
||||
destroy(
|
||||
begin(), end());
|
||||
t_->size = 0;
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
value const& v) ->
|
||||
iterator
|
||||
{
|
||||
return emplace(pos, v);
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
value&& v) ->
|
||||
iterator
|
||||
{
|
||||
return emplace(pos, std::move(v));
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
std::size_t count,
|
||||
value const& v) ->
|
||||
iterator
|
||||
{
|
||||
revert_insert r(
|
||||
pos, count, *this);
|
||||
while(count--)
|
||||
{
|
||||
::new(r.p) value(v, sp_);
|
||||
++r.p;
|
||||
}
|
||||
return r.commit();
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
std::initializer_list<
|
||||
value_ref> init) ->
|
||||
iterator
|
||||
{
|
||||
revert_insert r(
|
||||
pos, init.size(), *this);
|
||||
value_ref::write_array(
|
||||
r.p, init, sp_);
|
||||
return r.commit();
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
erase(
|
||||
const_iterator pos) noexcept ->
|
||||
iterator
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
pos >= begin() &&
|
||||
pos <= end());
|
||||
return erase(pos, pos + 1);
|
||||
}
|
||||
|
||||
auto
|
||||
array::
|
||||
erase(
|
||||
const_iterator first,
|
||||
const_iterator last) noexcept ->
|
||||
iterator
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
first >= begin() &&
|
||||
last >= first &&
|
||||
last <= end());
|
||||
std::size_t const n =
|
||||
last - first;
|
||||
auto const p = &(*t_)[0] +
|
||||
(first - &(*t_)[0]);
|
||||
destroy(p, p + n);
|
||||
relocate(p, p + n,
|
||||
t_->size - (last -
|
||||
&(*t_)[0]));
|
||||
t_->size = static_cast<
|
||||
std::uint32_t>(t_->size - n);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
push_back(value const& v)
|
||||
{
|
||||
emplace_back(v);
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
push_back(value&& v)
|
||||
{
|
||||
emplace_back(std::move(v));
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
pop_back() noexcept
|
||||
{
|
||||
auto const p = &back();
|
||||
destroy(p, p + 1);
|
||||
--t_->size;
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
resize(std::size_t count)
|
||||
{
|
||||
if(count <= t_->size)
|
||||
{
|
||||
// shrink
|
||||
destroy(
|
||||
&(*t_)[0] + count,
|
||||
&(*t_)[0] + t_->size);
|
||||
t_->size = static_cast<
|
||||
std::uint32_t>(count);
|
||||
return;
|
||||
}
|
||||
|
||||
reserve(count);
|
||||
auto p = &(*t_)[t_->size];
|
||||
auto const end = &(*t_)[count];
|
||||
while(p != end)
|
||||
::new(p++) value(sp_);
|
||||
t_->size = static_cast<
|
||||
std::uint32_t>(count);
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
resize(
|
||||
std::size_t count,
|
||||
value const& v)
|
||||
{
|
||||
if(count <= size())
|
||||
{
|
||||
// shrink
|
||||
destroy(
|
||||
data() + count,
|
||||
data() + size());
|
||||
t_->size = static_cast<
|
||||
std::uint32_t>(count);
|
||||
return;
|
||||
}
|
||||
count -= size();
|
||||
revert_insert r(
|
||||
end(), count, *this);
|
||||
while(count--)
|
||||
{
|
||||
::new(r.p) value(v, sp_);
|
||||
++r.p;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
void
|
||||
array::
|
||||
swap(array& other)
|
||||
{
|
||||
if(*sp_ == *other.sp_)
|
||||
{
|
||||
t_ = detail::exchange(
|
||||
other.t_, t_);
|
||||
return;
|
||||
}
|
||||
array temp1(
|
||||
std::move(*this),
|
||||
other.storage());
|
||||
array temp2(
|
||||
std::move(other),
|
||||
this->storage());
|
||||
this->~array();
|
||||
::new(this) array(
|
||||
pilfer(temp2));
|
||||
other.~array();
|
||||
::new(&other) array(
|
||||
pilfer(temp1));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Private
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
std::size_t
|
||||
array::
|
||||
growth(
|
||||
std::size_t new_size) const
|
||||
{
|
||||
if(new_size > max_size())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::array_too_large, &loc );
|
||||
}
|
||||
std::size_t const old = capacity();
|
||||
if(old > max_size() - old / 2)
|
||||
return new_size;
|
||||
std::size_t const g =
|
||||
old + old / 2; // 1.5x
|
||||
if(g < new_size)
|
||||
return new_size;
|
||||
return g;
|
||||
}
|
||||
|
||||
// precondition: new_capacity > capacity()
|
||||
void
|
||||
array::
|
||||
reserve_impl(
|
||||
std::size_t new_capacity)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
new_capacity > t_->capacity);
|
||||
auto t = table::allocate(
|
||||
growth(new_capacity), sp_);
|
||||
relocate(
|
||||
&(*t)[0],
|
||||
&(*t_)[0],
|
||||
t_->size);
|
||||
t->size = t_->size;
|
||||
t = detail::exchange(t_, t);
|
||||
table::deallocate(t, sp_);
|
||||
}
|
||||
|
||||
// precondition: pv is not aliased
|
||||
value&
|
||||
array::
|
||||
push_back(
|
||||
pilfered<value> pv)
|
||||
{
|
||||
auto const n = t_->size;
|
||||
if(n < t_->capacity)
|
||||
{
|
||||
// fast path
|
||||
auto& v = *::new(
|
||||
&(*t_)[n]) value(pv);
|
||||
++t_->size;
|
||||
return v;
|
||||
}
|
||||
auto const t =
|
||||
detail::exchange(t_,
|
||||
table::allocate(
|
||||
growth(n + 1),
|
||||
sp_));
|
||||
auto& v = *::new(
|
||||
&(*t_)[n]) value(pv);
|
||||
relocate(
|
||||
&(*t_)[0],
|
||||
&(*t)[0],
|
||||
n);
|
||||
t_->size = n + 1;
|
||||
table::deallocate(t, sp_);
|
||||
return v;
|
||||
}
|
||||
|
||||
// precondition: pv is not aliased
|
||||
auto
|
||||
array::
|
||||
insert(
|
||||
const_iterator pos,
|
||||
pilfered<value> pv) ->
|
||||
iterator
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
pos >= begin() &&
|
||||
pos <= end());
|
||||
std::size_t const n =
|
||||
t_->size;
|
||||
std::size_t const i =
|
||||
pos - &(*t_)[0];
|
||||
if(n < t_->capacity)
|
||||
{
|
||||
// fast path
|
||||
auto const p =
|
||||
&(*t_)[i];
|
||||
relocate(
|
||||
p + 1,
|
||||
p,
|
||||
n - i);
|
||||
::new(p) value(pv);
|
||||
++t_->size;
|
||||
return p;
|
||||
}
|
||||
auto t =
|
||||
table::allocate(
|
||||
growth(n + 1), sp_);
|
||||
auto const p = &(*t)[i];
|
||||
::new(p) value(pv);
|
||||
relocate(
|
||||
&(*t)[0],
|
||||
&(*t_)[0],
|
||||
i);
|
||||
relocate(
|
||||
p + 1,
|
||||
&(*t_)[i],
|
||||
n - i);
|
||||
t->size = static_cast<
|
||||
std::uint32_t>(size() + 1);
|
||||
t = detail::exchange(t_, t);
|
||||
table::deallocate(t, sp_);
|
||||
return p;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
bool
|
||||
array::
|
||||
equal(
|
||||
array const& other) const noexcept
|
||||
{
|
||||
if(size() != other.size())
|
||||
return false;
|
||||
for(std::size_t i = 0; i < size(); ++i)
|
||||
if((*this)[i] != other[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// std::hash specialization
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
std::size_t
|
||||
std::hash<::boost::json::array>::operator()(
|
||||
::boost::json::array const& ja) const noexcept
|
||||
{
|
||||
return ::boost::hash< ::boost::json::array >()( ja );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
#endif
|
||||
+545
@@ -0,0 +1,545 @@
|
||||
//
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
|
||||
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_CONVERSION_HPP
|
||||
#define BOOST_JSON_IMPL_CONVERSION_HPP
|
||||
|
||||
#include <boost/json/fwd.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/string_view.hpp>
|
||||
#include <boost/describe/enumerators.hpp>
|
||||
#include <boost/describe/members.hpp>
|
||||
#include <boost/describe/bases.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/utility.hpp>
|
||||
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#ifndef BOOST_NO_CXX17_HDR_VARIANT
|
||||
# include <variant>
|
||||
#endif // BOOST_NO_CXX17_HDR_VARIANT
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
#ifdef __cpp_lib_nonmember_container_access
|
||||
using std::size;
|
||||
#endif
|
||||
|
||||
template<std::size_t I, class T>
|
||||
using tuple_element_t = typename std::tuple_element<I, T>::type;
|
||||
|
||||
template<class T>
|
||||
using iterator_type = decltype(std::begin(std::declval<T&>()));
|
||||
template<class T>
|
||||
using iterator_traits = std::iterator_traits< iterator_type<T> >;
|
||||
|
||||
template<class T>
|
||||
using value_type = typename iterator_traits<T>::value_type;
|
||||
template<class T>
|
||||
using mapped_type = tuple_element_t< 1, value_type<T> >;
|
||||
|
||||
// had to make the metafunction always succeeding in order to make it work
|
||||
// with msvc 14.0
|
||||
template<class T>
|
||||
using key_type_helper = tuple_element_t< 0, value_type<T> >;
|
||||
template<class T>
|
||||
using key_type = mp11::mp_eval_or<
|
||||
void,
|
||||
key_type_helper,
|
||||
T>;
|
||||
|
||||
template<class T>
|
||||
using are_begin_and_end_same = std::is_same<
|
||||
iterator_type<T>,
|
||||
decltype(std::end(std::declval<T&>()))>;
|
||||
|
||||
template<class T>
|
||||
using begin_iterator_category = typename std::iterator_traits<
|
||||
iterator_type<T>>::iterator_category;
|
||||
|
||||
template<class T>
|
||||
using has_positive_tuple_size = mp11::mp_bool<
|
||||
(std::tuple_size<T>::value > 0) >;
|
||||
|
||||
template<class T>
|
||||
using has_unique_keys = has_positive_tuple_size<decltype(
|
||||
std::declval<T&>().emplace(
|
||||
std::declval<value_type<T>>()))>;
|
||||
|
||||
template<class T>
|
||||
struct is_value_type_pair_helper : std::false_type
|
||||
{ };
|
||||
template<class T1, class T2>
|
||||
struct is_value_type_pair_helper<std::pair<T1, T2>> : std::true_type
|
||||
{ };
|
||||
template<class T>
|
||||
using is_value_type_pair = is_value_type_pair_helper<value_type<T>>;
|
||||
|
||||
template<class T>
|
||||
using has_size_member_helper
|
||||
= std::is_convertible<decltype(std::declval<T&>().size()), std::size_t>;
|
||||
template<class T>
|
||||
using has_size_member = mp11::mp_valid_and_true<has_size_member_helper, T>;
|
||||
template<class T>
|
||||
using has_free_size_helper
|
||||
= std::is_convertible<
|
||||
decltype(size(std::declval<T const&>())),
|
||||
std::size_t>;
|
||||
template<class T>
|
||||
using has_free_size = mp11::mp_valid_and_true<has_free_size_helper, T>;
|
||||
template<class T>
|
||||
using size_implementation = mp11::mp_cond<
|
||||
has_size_member<T>, mp11::mp_int<3>,
|
||||
has_free_size<T>, mp11::mp_int<2>,
|
||||
std::is_array<T>, mp11::mp_int<1>,
|
||||
mp11::mp_true, mp11::mp_int<0>>;
|
||||
|
||||
template<class T>
|
||||
std::size_t
|
||||
try_size(T&& cont, mp11::mp_int<3>)
|
||||
{
|
||||
return cont.size();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::size_t
|
||||
try_size(T& cont, mp11::mp_int<2>)
|
||||
{
|
||||
return size(cont);
|
||||
}
|
||||
|
||||
template<class T, std::size_t N>
|
||||
std::size_t
|
||||
try_size(T(&)[N], mp11::mp_int<1>)
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::size_t
|
||||
try_size(T&, mp11::mp_int<0>)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
using has_push_back_helper
|
||||
= decltype(std::declval<T&>().push_back(std::declval<value_type<T>>()));
|
||||
template<class T>
|
||||
using has_push_back = mp11::mp_valid<has_push_back_helper, T>;
|
||||
template<class T>
|
||||
using inserter_implementation = mp11::mp_cond<
|
||||
is_tuple_like<T>, mp11::mp_int<2>,
|
||||
has_push_back<T>, mp11::mp_int<1>,
|
||||
mp11::mp_true, mp11::mp_int<0>>;
|
||||
|
||||
template<class T>
|
||||
iterator_type<T>
|
||||
inserter(
|
||||
T& target,
|
||||
mp11::mp_int<2>)
|
||||
{
|
||||
return target.begin();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::back_insert_iterator<T>
|
||||
inserter(
|
||||
T& target,
|
||||
mp11::mp_int<1>)
|
||||
{
|
||||
return std::back_inserter(target);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::insert_iterator<T>
|
||||
inserter(
|
||||
T& target,
|
||||
mp11::mp_int<0>)
|
||||
{
|
||||
return std::inserter( target, target.end() );
|
||||
}
|
||||
|
||||
using value_from_conversion = mp11::mp_true;
|
||||
using value_to_conversion = mp11::mp_false;
|
||||
|
||||
struct user_conversion_tag { };
|
||||
struct context_conversion_tag : user_conversion_tag { };
|
||||
struct full_context_conversion_tag : context_conversion_tag { };
|
||||
struct native_conversion_tag { };
|
||||
struct value_conversion_tag : native_conversion_tag { };
|
||||
struct object_conversion_tag : native_conversion_tag { };
|
||||
struct array_conversion_tag : native_conversion_tag { };
|
||||
struct string_conversion_tag : native_conversion_tag { };
|
||||
struct bool_conversion_tag : native_conversion_tag { };
|
||||
struct number_conversion_tag : native_conversion_tag { };
|
||||
struct integral_conversion_tag : number_conversion_tag { };
|
||||
struct floating_point_conversion_tag : number_conversion_tag { };
|
||||
struct null_like_conversion_tag { };
|
||||
struct string_like_conversion_tag { };
|
||||
struct map_like_conversion_tag { };
|
||||
struct sequence_conversion_tag { };
|
||||
struct tuple_conversion_tag { };
|
||||
struct described_class_conversion_tag { };
|
||||
struct described_enum_conversion_tag { };
|
||||
struct variant_conversion_tag { };
|
||||
struct optional_conversion_tag { };
|
||||
struct no_conversion_tag { };
|
||||
|
||||
template<class... Args>
|
||||
using supports_tag_invoke = decltype(tag_invoke( std::declval<Args>()... ));
|
||||
|
||||
template<class T>
|
||||
using has_user_conversion_from_impl = supports_tag_invoke<
|
||||
value_from_tag, value&, T&& >;
|
||||
template<class T>
|
||||
using has_user_conversion_to_impl = supports_tag_invoke<
|
||||
value_to_tag<T>, value const& >;
|
||||
template<class T>
|
||||
using has_nonthrowing_user_conversion_to_impl = supports_tag_invoke<
|
||||
try_value_to_tag<T>, value const& >;
|
||||
template< class T, class Dir >
|
||||
using has_user_conversion1 = mp11::mp_if<
|
||||
std::is_same<Dir, value_from_conversion>,
|
||||
mp11::mp_valid<has_user_conversion_from_impl, T>,
|
||||
mp11::mp_or<
|
||||
mp11::mp_valid<has_user_conversion_to_impl, T>,
|
||||
mp11::mp_valid<has_nonthrowing_user_conversion_to_impl, T>>>;
|
||||
|
||||
template< class Ctx, class T >
|
||||
using has_context_conversion_from_impl = supports_tag_invoke<
|
||||
value_from_tag, value&, T&&, Ctx const& >;
|
||||
template< class Ctx, class T >
|
||||
using has_context_conversion_to_impl = supports_tag_invoke<
|
||||
value_to_tag<T>, value const&, Ctx const& >;
|
||||
template< class Ctx, class T >
|
||||
using has_nonthrowing_context_conversion_to_impl = supports_tag_invoke<
|
||||
try_value_to_tag<T>, value const&, Ctx const& >;
|
||||
template< class Ctx, class T, class Dir >
|
||||
using has_user_conversion2 = mp11::mp_if<
|
||||
std::is_same<Dir, value_from_conversion>,
|
||||
mp11::mp_valid<has_context_conversion_from_impl, Ctx, T>,
|
||||
mp11::mp_or<
|
||||
mp11::mp_valid<has_context_conversion_to_impl, Ctx, T>,
|
||||
mp11::mp_valid<has_nonthrowing_context_conversion_to_impl, Ctx, T>>>;
|
||||
|
||||
template< class Ctx, class T >
|
||||
using has_full_context_conversion_from_impl = supports_tag_invoke<
|
||||
value_from_tag, value&, T&&, Ctx const&, Ctx const& >;
|
||||
template< class Ctx, class T >
|
||||
using has_full_context_conversion_to_impl = supports_tag_invoke<
|
||||
value_to_tag<T>, value const&, Ctx const&, Ctx const& >;
|
||||
template< class Ctx, class T >
|
||||
using has_nonthrowing_full_context_conversion_to_impl = supports_tag_invoke<
|
||||
try_value_to_tag<T>, value const&, Ctx const&, Ctx const& >;
|
||||
template< class Ctx, class T, class Dir >
|
||||
using has_user_conversion3 = mp11::mp_if<
|
||||
std::is_same<Dir, value_from_conversion>,
|
||||
mp11::mp_valid<has_full_context_conversion_from_impl, Ctx, T>,
|
||||
mp11::mp_or<
|
||||
mp11::mp_valid<has_full_context_conversion_to_impl, Ctx, T>,
|
||||
mp11::mp_valid<
|
||||
has_nonthrowing_full_context_conversion_to_impl, Ctx, T>>>;
|
||||
|
||||
template< class T >
|
||||
using described_non_public_members = describe::describe_members<
|
||||
T, describe::mod_private | describe::mod_protected>;
|
||||
template< class T >
|
||||
using described_bases = describe::describe_bases<
|
||||
T, describe::mod_any_access>;
|
||||
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC < 1920
|
||||
|
||||
template< class T >
|
||||
struct described_member_t_impl;
|
||||
|
||||
template< class T, class C >
|
||||
struct described_member_t_impl<T C::*>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template< class T, class D >
|
||||
using described_member_t = remove_cvref<
|
||||
typename described_member_t_impl<
|
||||
remove_cvref<decltype(D::pointer)> >::type>;
|
||||
|
||||
#else
|
||||
|
||||
template< class T, class D >
|
||||
using described_member_t = remove_cvref<decltype(
|
||||
std::declval<T&>().* D::pointer )>;
|
||||
|
||||
#endif
|
||||
|
||||
// user conversion (via tag_invoke)
|
||||
template< class Ctx, class T, class Dir >
|
||||
using user_conversion_category = mp11::mp_cond<
|
||||
has_user_conversion3<Ctx, T, Dir>, full_context_conversion_tag,
|
||||
has_user_conversion2<Ctx, T, Dir>, context_conversion_tag,
|
||||
has_user_conversion1<T, Dir>, user_conversion_tag>;
|
||||
|
||||
// native conversions (constructors and member functions of value)
|
||||
template< class T >
|
||||
using native_conversion_category = mp11::mp_cond<
|
||||
std::is_same<T, value>, value_conversion_tag,
|
||||
std::is_same<T, array>, array_conversion_tag,
|
||||
std::is_same<T, object>, object_conversion_tag,
|
||||
std::is_same<T, string>, string_conversion_tag>;
|
||||
|
||||
// generic conversions
|
||||
template< class T >
|
||||
using generic_conversion_category = mp11::mp_cond<
|
||||
std::is_same<T, bool>, bool_conversion_tag,
|
||||
std::is_integral<T>, integral_conversion_tag,
|
||||
std::is_floating_point<T>, floating_point_conversion_tag,
|
||||
is_null_like<T>, null_like_conversion_tag,
|
||||
is_string_like<T>, string_like_conversion_tag,
|
||||
is_map_like<T>, map_like_conversion_tag,
|
||||
is_sequence_like<T>, sequence_conversion_tag,
|
||||
is_tuple_like<T>, tuple_conversion_tag,
|
||||
is_described_class<T>, described_class_conversion_tag,
|
||||
is_described_enum<T>, described_enum_conversion_tag,
|
||||
is_variant_like<T>, variant_conversion_tag,
|
||||
is_optional_like<T>, optional_conversion_tag,
|
||||
// failed to find a suitable implementation
|
||||
mp11::mp_true, no_conversion_tag>;
|
||||
|
||||
template< class T >
|
||||
using nested_type = typename T::type;
|
||||
template< class T1, class T2 >
|
||||
using conversion_category_impl_helper = mp11::mp_eval_if_not<
|
||||
std::is_same<detail::no_conversion_tag, T1>,
|
||||
T1,
|
||||
mp11::mp_eval_or_q, T1, mp11::mp_quote<nested_type>, T2>;
|
||||
template< class Ctx, class T, class Dir >
|
||||
struct conversion_category_impl
|
||||
{
|
||||
using type = mp11::mp_fold<
|
||||
mp11::mp_list<
|
||||
mp11::mp_defer<user_conversion_category, Ctx, T, Dir>,
|
||||
mp11::mp_defer<native_conversion_category, T>,
|
||||
mp11::mp_defer<generic_conversion_category, T>>,
|
||||
no_conversion_tag,
|
||||
conversion_category_impl_helper>;
|
||||
};
|
||||
template< class Ctx, class T, class Dir >
|
||||
using conversion_category =
|
||||
typename conversion_category_impl< Ctx, T, Dir >::type;
|
||||
|
||||
template< class T >
|
||||
using any_conversion_tag = mp11::mp_not<
|
||||
std::is_same< T, no_conversion_tag > >;
|
||||
|
||||
template< class T, class Dir, class... Ctxs >
|
||||
struct conversion_category_impl< std::tuple<Ctxs...>, T, Dir >
|
||||
{
|
||||
using ctxs = mp11::mp_list< remove_cvref<Ctxs>... >;
|
||||
using cats = mp11::mp_list<
|
||||
conversion_category<remove_cvref<Ctxs>, T, Dir>... >;
|
||||
|
||||
template< class I >
|
||||
using exists = mp11::mp_less< I, mp11::mp_size<cats> >;
|
||||
|
||||
using context2 = mp11::mp_find< cats, full_context_conversion_tag >;
|
||||
using context1 = mp11::mp_find< cats, context_conversion_tag >;
|
||||
using context0 = mp11::mp_find< cats, user_conversion_tag >;
|
||||
using index = mp11::mp_cond<
|
||||
exists<context2>, context2,
|
||||
exists<context1>, context1,
|
||||
exists<context0>, context0,
|
||||
mp11::mp_true, mp11::mp_find_if< cats, any_conversion_tag > >;
|
||||
using type = mp11::mp_eval_or<
|
||||
no_conversion_tag,
|
||||
mp11::mp_at, cats, index >;
|
||||
};
|
||||
|
||||
struct no_context
|
||||
{};
|
||||
|
||||
struct allow_exceptions
|
||||
{};
|
||||
|
||||
template <class T, class Dir>
|
||||
using can_convert = mp11::mp_not<
|
||||
std::is_same<
|
||||
detail::conversion_category<no_context, T, Dir>,
|
||||
detail::no_conversion_tag>>;
|
||||
|
||||
template<class Impl1, class Impl2>
|
||||
using conversion_round_trips_helper = mp11::mp_or<
|
||||
std::is_same<Impl1, Impl2>,
|
||||
std::is_base_of<user_conversion_tag, Impl1>,
|
||||
std::is_base_of<user_conversion_tag, Impl2>>;
|
||||
template< class Ctx, class T, class Dir >
|
||||
using conversion_round_trips = conversion_round_trips_helper<
|
||||
conversion_category<Ctx, T, Dir>,
|
||||
conversion_category<Ctx, T, mp11::mp_not<Dir>>>;
|
||||
|
||||
template< class T1, class T2 >
|
||||
struct copy_cref_helper
|
||||
{
|
||||
using type = remove_cvref<T2>;
|
||||
};
|
||||
template< class T1, class T2 >
|
||||
using copy_cref = typename copy_cref_helper< T1, T2 >::type;
|
||||
|
||||
template< class T1, class T2 >
|
||||
struct copy_cref_helper<T1 const, T2>
|
||||
{
|
||||
using type = remove_cvref<T2> const;
|
||||
};
|
||||
template< class T1, class T2 >
|
||||
struct copy_cref_helper<T1&, T2>
|
||||
{
|
||||
using type = copy_cref<T1, T2>&;
|
||||
};
|
||||
template< class T1, class T2 >
|
||||
struct copy_cref_helper<T1&&, T2>
|
||||
{
|
||||
using type = copy_cref<T1, T2>&&;
|
||||
};
|
||||
|
||||
template< class Rng, class Traits >
|
||||
using forwarded_value_helper = mp11::mp_if<
|
||||
std::is_convertible<
|
||||
typename Traits::reference,
|
||||
copy_cref<Rng, typename Traits::value_type> >,
|
||||
copy_cref<Rng, typename Traits::value_type>,
|
||||
typename Traits::value_type >;
|
||||
|
||||
template< class Rng >
|
||||
using forwarded_value = forwarded_value_helper<
|
||||
Rng, iterator_traits< Rng > >;
|
||||
|
||||
template< class Ctx, class T, class Dir >
|
||||
struct supported_context
|
||||
{
|
||||
using type = Ctx;
|
||||
|
||||
static
|
||||
type const&
|
||||
get( Ctx const& ctx ) noexcept
|
||||
{
|
||||
return ctx;
|
||||
}
|
||||
};
|
||||
|
||||
template< class T, class Dir, class... Ctxs >
|
||||
struct supported_context< std::tuple<Ctxs...>, T, Dir >
|
||||
{
|
||||
using Ctx = std::tuple<Ctxs...>;
|
||||
using impl = conversion_category_impl<Ctx, T, Dir>;
|
||||
using index = typename impl::index;
|
||||
using next_supported = supported_context<
|
||||
mp11::mp_at< typename impl::ctxs, index >, T, Dir >;
|
||||
using type = typename next_supported::type;
|
||||
|
||||
static
|
||||
type const&
|
||||
get( Ctx const& ctx ) noexcept
|
||||
{
|
||||
return next_supported::get( std::get<index::value>( ctx ) );
|
||||
}
|
||||
};
|
||||
|
||||
template< class T >
|
||||
using value_result_type = typename std::decay<
|
||||
decltype( std::declval<T&>().value() )>::type;
|
||||
|
||||
template< class T >
|
||||
using can_reset = decltype( std::declval<T&>().reset() );
|
||||
|
||||
template< class T >
|
||||
using has_valueless_by_exception =
|
||||
decltype( std::declval<T const&>().valueless_by_exception() );
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
struct result_for<T, value>
|
||||
{
|
||||
using type = result< detail::remove_cvref<T> >;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct is_string_like
|
||||
: std::is_convertible<T, string_view>
|
||||
{ };
|
||||
|
||||
template<class T>
|
||||
struct is_sequence_like
|
||||
: mp11::mp_all<
|
||||
mp11::mp_valid_and_true<detail::are_begin_and_end_same, T>,
|
||||
mp11::mp_valid<detail::begin_iterator_category, T>>
|
||||
{ };
|
||||
|
||||
template<class T>
|
||||
struct is_map_like
|
||||
: mp11::mp_all<
|
||||
is_sequence_like<T>,
|
||||
mp11::mp_valid_and_true<detail::is_value_type_pair, T>,
|
||||
is_string_like<detail::key_type<T>>,
|
||||
mp11::mp_valid_and_true<detail::has_unique_keys, T>>
|
||||
{ };
|
||||
|
||||
template<class T>
|
||||
struct is_tuple_like
|
||||
: mp11::mp_valid_and_true<detail::has_positive_tuple_size, T>
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct is_null_like<std::nullptr_t>
|
||||
: std::true_type
|
||||
{ };
|
||||
|
||||
#ifndef BOOST_NO_CXX17_HDR_VARIANT
|
||||
template<>
|
||||
struct is_null_like<std::monostate>
|
||||
: std::true_type
|
||||
{ };
|
||||
#endif // BOOST_NO_CXX17_HDR_VARIANT
|
||||
|
||||
template<class T>
|
||||
struct is_described_class
|
||||
: mp11::mp_and<
|
||||
describe::has_describe_members<T>,
|
||||
mp11::mp_not< std::is_union<T> >,
|
||||
mp11::mp_empty<
|
||||
mp11::mp_eval_or<
|
||||
mp11::mp_list<>, detail::described_non_public_members, T>>,
|
||||
mp11::mp_empty<
|
||||
mp11::mp_eval_or<mp11::mp_list<>, detail::described_bases, T>>>
|
||||
{ };
|
||||
|
||||
template<class T>
|
||||
struct is_described_enum
|
||||
: describe::has_describe_enumerators<T>
|
||||
{ };
|
||||
|
||||
template<class T>
|
||||
struct is_variant_like : mp11::mp_valid<detail::has_valueless_by_exception, T>
|
||||
{ };
|
||||
|
||||
template<class T>
|
||||
struct is_optional_like
|
||||
: mp11::mp_and<
|
||||
mp11::mp_not<std::is_void<
|
||||
mp11::mp_eval_or<void, detail::value_result_type, T>>>,
|
||||
mp11::mp_valid<detail::can_reset, T>>
|
||||
{ };
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_JSON_IMPL_CONVERSION_HPP
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_ERROR_HPP
|
||||
#define BOOST_JSON_IMPL_ERROR_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace system {
|
||||
template<>
|
||||
struct is_error_code_enum< ::boost::json::error >
|
||||
{
|
||||
static bool const value = true;
|
||||
};
|
||||
template<>
|
||||
struct is_error_condition_enum< ::boost::json::condition >
|
||||
{
|
||||
static bool const value = true;
|
||||
};
|
||||
} // system
|
||||
} // boost
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct is_error_code_enum< ::boost::json::error >
|
||||
{
|
||||
static bool const value = true;
|
||||
};
|
||||
template<>
|
||||
struct is_error_condition_enum< ::boost::json::condition >
|
||||
{
|
||||
static bool const value = true;
|
||||
};
|
||||
} // std
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
struct error_code_category_t
|
||||
: error_category
|
||||
{
|
||||
constexpr
|
||||
error_code_category_t()
|
||||
: error_category(0xB9A9B9922177C772)
|
||||
{}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
const char*
|
||||
name() const noexcept override;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
char const*
|
||||
message( int ev, char* buf, std::size_t len ) const noexcept override;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::string
|
||||
message( int ev ) const override;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
error_condition
|
||||
default_error_condition( int ev ) const noexcept override;
|
||||
};
|
||||
|
||||
extern
|
||||
BOOST_JSON_DECL
|
||||
error_code_category_t error_code_category;
|
||||
|
||||
struct error_condition_category_t
|
||||
: error_category
|
||||
{
|
||||
constexpr
|
||||
error_condition_category_t()
|
||||
: error_category(0x37CEF5A036D24FD1)
|
||||
{}
|
||||
|
||||
BOOST_JSON_DECL
|
||||
const char*
|
||||
name() const noexcept override;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
char const*
|
||||
message( int ev, char*, std::size_t ) const noexcept override;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::string
|
||||
message( int cv ) const override;
|
||||
};
|
||||
|
||||
extern
|
||||
BOOST_JSON_DECL
|
||||
error_condition_category_t error_condition_category;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline
|
||||
BOOST_SYSTEM_CONSTEXPR
|
||||
error_code
|
||||
make_error_code(error e) noexcept
|
||||
{
|
||||
|
||||
return error_code(
|
||||
static_cast<std::underlying_type<error>::type>(e),
|
||||
detail::error_code_category );
|
||||
}
|
||||
|
||||
inline
|
||||
BOOST_SYSTEM_CONSTEXPR
|
||||
error_condition
|
||||
make_error_condition(condition c) noexcept
|
||||
{
|
||||
return error_condition(
|
||||
static_cast<std::underlying_type<condition>::type>(c),
|
||||
detail::error_condition_category );
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_ERROR_IPP
|
||||
#define BOOST_JSON_IMPL_ERROR_IPP
|
||||
|
||||
#include <boost/json/error.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
// msvc 14.0 has a bug that warns about inability to use constexpr
|
||||
// construction here, even though there's no constexpr construction
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1900
|
||||
# pragma warning( push )
|
||||
# pragma warning( disable : 4592 )
|
||||
#endif
|
||||
BOOST_JSON_CONSTINIT
|
||||
error_code_category_t error_code_category;
|
||||
|
||||
BOOST_JSON_CONSTINIT
|
||||
error_condition_category_t error_condition_category;
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1900
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
char const*
|
||||
error_code_category_t::name() const noexcept
|
||||
{
|
||||
return "boost.json";
|
||||
}
|
||||
|
||||
char const*
|
||||
error_code_category_t::message( int ev, char*, std::size_t ) const noexcept
|
||||
{
|
||||
switch(static_cast<error>(ev))
|
||||
{
|
||||
default:
|
||||
case error::syntax: return "syntax error";
|
||||
case error::extra_data: return "extra data";
|
||||
case error::incomplete: return "incomplete JSON";
|
||||
case error::exponent_overflow: return "exponent overflow";
|
||||
case error::too_deep: return "too deep";
|
||||
case error::illegal_leading_surrogate: return "illegal leading surrogate";
|
||||
case error::illegal_trailing_surrogate: return "illegal trailing surrogate";
|
||||
case error::expected_hex_digit: return "expected hex digit";
|
||||
case error::expected_utf16_escape: return "expected utf16 escape";
|
||||
case error::object_too_large: return "object too large";
|
||||
case error::array_too_large: return "array too large";
|
||||
case error::key_too_large: return "key too large";
|
||||
case error::string_too_large: return "string too large";
|
||||
case error::number_too_large: return "number too large";
|
||||
case error::input_error: return "input error";
|
||||
|
||||
case error::exception: return "got exception";
|
||||
case error::out_of_range: return "out of range";
|
||||
case error::test_failure: return "test failure";
|
||||
|
||||
case error::missing_slash: return "missing slash character";
|
||||
case error::invalid_escape: return "invalid escape sequence";
|
||||
case error::token_not_number: return "token is not a number";
|
||||
case error::value_is_scalar: return "current value is scalar";
|
||||
case error::not_found: return "no referenced value";
|
||||
case error::token_overflow: return "token overflow";
|
||||
case error::past_the_end: return "past-the-end token not supported";
|
||||
|
||||
case error::not_number: return "not a number";
|
||||
case error::not_exact: return "not exact";
|
||||
case error::not_null: return "value is not null";
|
||||
case error::not_bool: return "value is not boolean";
|
||||
case error::not_array: return "value is not an array";
|
||||
case error::not_object: return "value is not an object";
|
||||
case error::not_string: return "value is not a string";
|
||||
case error::not_int64: return "value is not a std::int64_t number";
|
||||
case error::not_uint64: return "value is not a std::uint64_t number";
|
||||
case error::not_double: return "value is not a double";
|
||||
case error::not_integer: return "value is not integer";
|
||||
case error::size_mismatch: return "source composite size does not match target size";
|
||||
case error::exhausted_variants: return "exhausted all variants";
|
||||
case error::unknown_name: return "unknown name";
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
error_code_category_t::message( int ev ) const
|
||||
{
|
||||
return message( ev, nullptr, 0 );
|
||||
}
|
||||
|
||||
error_condition
|
||||
error_code_category_t::default_error_condition( int ev) const noexcept
|
||||
{
|
||||
switch(static_cast<error>(ev))
|
||||
{
|
||||
default:
|
||||
return {ev, *this};
|
||||
|
||||
case error::syntax:
|
||||
case error::extra_data:
|
||||
case error::incomplete:
|
||||
case error::exponent_overflow:
|
||||
case error::too_deep:
|
||||
case error::illegal_leading_surrogate:
|
||||
case error::illegal_trailing_surrogate:
|
||||
case error::expected_hex_digit:
|
||||
case error::expected_utf16_escape:
|
||||
case error::object_too_large:
|
||||
case error::array_too_large:
|
||||
case error::key_too_large:
|
||||
case error::string_too_large:
|
||||
case error::number_too_large:
|
||||
case error::input_error:
|
||||
return condition::parse_error;
|
||||
|
||||
case error::missing_slash:
|
||||
case error::invalid_escape:
|
||||
return condition::pointer_parse_error;
|
||||
|
||||
case error::token_not_number:
|
||||
case error::value_is_scalar:
|
||||
case error::not_found:
|
||||
case error::token_overflow:
|
||||
case error::past_the_end:
|
||||
return condition::pointer_use_error;
|
||||
|
||||
case error::not_number:
|
||||
case error::not_exact:
|
||||
case error::not_null:
|
||||
case error::not_bool:
|
||||
case error::not_array:
|
||||
case error::not_object:
|
||||
case error::not_string:
|
||||
case error::not_int64:
|
||||
case error::not_uint64:
|
||||
case error::not_double:
|
||||
case error::not_integer:
|
||||
case error::size_mismatch:
|
||||
case error::exhausted_variants:
|
||||
case error::unknown_name:
|
||||
return condition::conversion_error;
|
||||
|
||||
case error::exception:
|
||||
case error::out_of_range:
|
||||
return condition::generic_error;
|
||||
}
|
||||
}
|
||||
|
||||
char const*
|
||||
error_condition_category_t::name() const noexcept
|
||||
{
|
||||
return "boost.json";
|
||||
}
|
||||
|
||||
char const*
|
||||
error_condition_category_t::message( int cv, char*, std::size_t ) const noexcept
|
||||
{
|
||||
switch(static_cast<condition>(cv))
|
||||
{
|
||||
default:
|
||||
case condition::parse_error:
|
||||
return "A JSON parse error occurred";
|
||||
case condition::pointer_parse_error:
|
||||
return "A JSON Pointer parse error occurred";
|
||||
case condition::pointer_use_error:
|
||||
return "An error occurred when JSON Pointer was used with"
|
||||
" a value";
|
||||
case condition::conversion_error:
|
||||
return "An error occurred during conversion";
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
error_condition_category_t::message( int cv ) const
|
||||
{
|
||||
return message( cv, nullptr, 0 );
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_KIND_IPP
|
||||
#define BOOST_JSON_IMPL_KIND_IPP
|
||||
|
||||
#include <boost/json/kind.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
string_view
|
||||
to_string(kind k) noexcept
|
||||
{
|
||||
switch(k)
|
||||
{
|
||||
case kind::array: return "array";
|
||||
case kind::object: return "object";
|
||||
case kind::string: return "string";
|
||||
case kind::int64: return "int64";
|
||||
case kind::uint64: return "uint64";
|
||||
case kind::double_: return "double";
|
||||
case kind::bool_: return "bool";
|
||||
default: // satisfy warnings
|
||||
case kind::null: return "null";
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, kind k)
|
||||
{
|
||||
os << to_string(k);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
|
||||
#define BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
|
||||
|
||||
#include <boost/json/monotonic_resource.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <boost/align/align.hpp>
|
||||
#include <boost/core/max_align.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
struct alignas(core::max_align_t)
|
||||
monotonic_resource::block : block_base
|
||||
{
|
||||
};
|
||||
|
||||
constexpr
|
||||
std::size_t
|
||||
monotonic_resource::
|
||||
max_size()
|
||||
{
|
||||
return std::size_t(-1) - sizeof(block);
|
||||
}
|
||||
|
||||
// lowest power of 2 greater than or equal to n
|
||||
std::size_t
|
||||
monotonic_resource::
|
||||
round_pow2(
|
||||
std::size_t n) noexcept
|
||||
{
|
||||
if(n & (n - 1))
|
||||
return next_pow2(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
// lowest power of 2 greater than n
|
||||
std::size_t
|
||||
monotonic_resource::
|
||||
next_pow2(
|
||||
std::size_t n) noexcept
|
||||
{
|
||||
std::size_t result = min_size_;
|
||||
while(result <= n)
|
||||
{
|
||||
if(result >= max_size() - result)
|
||||
{
|
||||
// overflow
|
||||
result = max_size();
|
||||
break;
|
||||
}
|
||||
result *= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
monotonic_resource::
|
||||
~monotonic_resource()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
monotonic_resource::
|
||||
monotonic_resource(
|
||||
std::size_t initial_size,
|
||||
storage_ptr upstream) noexcept
|
||||
: buffer_{
|
||||
nullptr, 0, 0, nullptr}
|
||||
, next_size_(round_pow2(initial_size))
|
||||
, upstream_(std::move(upstream))
|
||||
{
|
||||
}
|
||||
|
||||
monotonic_resource::
|
||||
monotonic_resource(
|
||||
unsigned char* buffer,
|
||||
std::size_t size,
|
||||
storage_ptr upstream) noexcept
|
||||
: buffer_{
|
||||
buffer, size, size, nullptr}
|
||||
, next_size_(next_pow2(size))
|
||||
, upstream_(std::move(upstream))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
monotonic_resource::
|
||||
release() noexcept
|
||||
{
|
||||
auto p = head_;
|
||||
while(p != &buffer_)
|
||||
{
|
||||
auto next = p->next;
|
||||
upstream_->deallocate(p, p->size);
|
||||
p = next;
|
||||
}
|
||||
buffer_.p = reinterpret_cast<
|
||||
unsigned char*>(buffer_.p) - (
|
||||
buffer_.size - buffer_.avail);
|
||||
buffer_.avail = buffer_.size;
|
||||
head_ = &buffer_;
|
||||
}
|
||||
|
||||
void*
|
||||
monotonic_resource::
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align)
|
||||
{
|
||||
auto p = alignment::align(
|
||||
align, n, head_->p, head_->avail);
|
||||
if(p)
|
||||
{
|
||||
head_->p = reinterpret_cast<
|
||||
unsigned char*>(p) + n;
|
||||
head_->avail -= n;
|
||||
return p;
|
||||
}
|
||||
|
||||
if(next_size_ < n)
|
||||
next_size_ = round_pow2(n);
|
||||
auto b = ::new(upstream_->allocate(
|
||||
sizeof(block) + next_size_)) block;
|
||||
b->p = b + 1;
|
||||
b->avail = next_size_;
|
||||
b->size = next_size_;
|
||||
b->next = head_;
|
||||
head_ = b;
|
||||
next_size_ = next_pow2(next_size_);
|
||||
|
||||
p = alignment::align(
|
||||
align, n, head_->p, head_->avail);
|
||||
BOOST_ASSERT(p);
|
||||
head_->p = reinterpret_cast<
|
||||
unsigned char*>(p) + n;
|
||||
head_->avail -= n;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
monotonic_resource::
|
||||
do_deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
bool
|
||||
monotonic_resource::
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept
|
||||
{
|
||||
return this == &mr;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_NULL_RESOURCE_IPP
|
||||
#define BOOST_JSON_IMPL_NULL_RESOURCE_IPP
|
||||
|
||||
#include <boost/json/null_resource.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/** A resource which always fails.
|
||||
|
||||
This memory resource always throws the exception
|
||||
`std::bad_alloc` in calls to `allocate`.
|
||||
*/
|
||||
class null_resource final
|
||||
: public memory_resource
|
||||
{
|
||||
public:
|
||||
/// Copy constructor (deleted)
|
||||
null_resource(
|
||||
null_resource const&) = delete;
|
||||
|
||||
/// Copy assignment (deleted)
|
||||
null_resource& operator=(
|
||||
null_resource const&) = delete;
|
||||
|
||||
/** Constructor
|
||||
|
||||
This constructs the resource.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
/** @{ */
|
||||
null_resource() noexcept = default;
|
||||
|
||||
protected:
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t,
|
||||
std::size_t) override
|
||||
{
|
||||
throw_exception( std::bad_alloc(), BOOST_CURRENT_LOCATION );
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t) override
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr
|
||||
) const noexcept override
|
||||
{
|
||||
return this == &mr;
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
memory_resource*
|
||||
get_null_resource() noexcept
|
||||
{
|
||||
static detail::null_resource mr;
|
||||
return &mr;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+587
@@ -0,0 +1,587 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_OBJECT_HPP
|
||||
#define BOOST_JSON_IMPL_OBJECT_HPP
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
#include <iterator>
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Objects with size less than or equal
|
||||
// to this number will use a linear search
|
||||
// instead of the more expensive hash function.
|
||||
static
|
||||
constexpr
|
||||
std::size_t
|
||||
small_object_size_ = 18;
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
small_object_size_ <
|
||||
BOOST_JSON_MAX_STRUCTURED_SIZE);
|
||||
|
||||
} // detail
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
struct alignas(key_value_pair)
|
||||
object::table
|
||||
{
|
||||
std::uint32_t size = 0;
|
||||
std::uint32_t capacity = 0;
|
||||
std::uintptr_t salt = 0;
|
||||
|
||||
#if defined(_MSC_VER) && BOOST_JSON_ARCH == 32
|
||||
// VFALCO If we make key_value_pair smaller,
|
||||
// then we might want to revisit this
|
||||
// padding.
|
||||
BOOST_STATIC_ASSERT(
|
||||
sizeof(key_value_pair) == 32);
|
||||
char pad[4] = {}; // silence warnings
|
||||
#endif
|
||||
|
||||
constexpr table();
|
||||
|
||||
// returns true if we use a linear
|
||||
// search instead of the hash table.
|
||||
bool is_small() const noexcept
|
||||
{
|
||||
return capacity <=
|
||||
detail::small_object_size_;
|
||||
}
|
||||
|
||||
key_value_pair&
|
||||
operator[](
|
||||
std::size_t pos) noexcept
|
||||
{
|
||||
return reinterpret_cast<
|
||||
key_value_pair*>(
|
||||
this + 1)[pos];
|
||||
}
|
||||
|
||||
// VFALCO This is exported for tests
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
digest(string_view key) const noexcept;
|
||||
|
||||
inline
|
||||
index_t&
|
||||
bucket(std::size_t hash) noexcept;
|
||||
|
||||
inline
|
||||
index_t&
|
||||
bucket(string_view key) noexcept;
|
||||
|
||||
inline
|
||||
void
|
||||
clear() noexcept;
|
||||
|
||||
static
|
||||
inline
|
||||
table*
|
||||
allocate(
|
||||
std::size_t capacity,
|
||||
std::uintptr_t salt,
|
||||
storage_ptr const& sp);
|
||||
|
||||
static
|
||||
void
|
||||
deallocate(
|
||||
table* p,
|
||||
storage_ptr const& sp) noexcept
|
||||
{
|
||||
if(p->capacity == 0)
|
||||
return;
|
||||
if(! p->is_small())
|
||||
sp->deallocate(p,
|
||||
sizeof(table) + p->capacity * (
|
||||
sizeof(key_value_pair) +
|
||||
sizeof(index_t)));
|
||||
else
|
||||
sp->deallocate(p,
|
||||
sizeof(table) + p->capacity *
|
||||
sizeof(key_value_pair));
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class object::revert_construct
|
||||
{
|
||||
object* obj_;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
destroy() noexcept;
|
||||
|
||||
public:
|
||||
explicit
|
||||
revert_construct(
|
||||
object& obj) noexcept
|
||||
: obj_(&obj)
|
||||
{
|
||||
}
|
||||
|
||||
~revert_construct()
|
||||
{
|
||||
if(! obj_)
|
||||
return;
|
||||
destroy();
|
||||
}
|
||||
|
||||
void
|
||||
commit() noexcept
|
||||
{
|
||||
obj_ = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class object::revert_insert
|
||||
{
|
||||
object* obj_;
|
||||
table* t_ = nullptr;
|
||||
std::size_t size_;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
destroy() noexcept;
|
||||
|
||||
public:
|
||||
explicit
|
||||
revert_insert(
|
||||
object& obj,
|
||||
std::size_t capacity)
|
||||
: obj_(&obj)
|
||||
, size_(obj_->size())
|
||||
{
|
||||
if( capacity > obj_->capacity() )
|
||||
t_ = obj_->reserve_impl(capacity);
|
||||
}
|
||||
|
||||
~revert_insert()
|
||||
{
|
||||
if(! obj_)
|
||||
return;
|
||||
|
||||
destroy();
|
||||
if( t_ )
|
||||
{
|
||||
table::deallocate( obj_->t_, obj_->sp_ );
|
||||
obj_->t_ = t_;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj_->t_->size = static_cast<index_t>(size_);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
commit() noexcept
|
||||
{
|
||||
BOOST_ASSERT(obj_);
|
||||
if( t_ )
|
||||
table::deallocate( t_, obj_->sp_ );
|
||||
obj_ = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Iterators
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
auto
|
||||
object::
|
||||
begin() noexcept ->
|
||||
iterator
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
begin() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
cbegin() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[0];
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
end() noexcept ->
|
||||
iterator
|
||||
{
|
||||
return &(*t_)[t_->size];
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
end() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[t_->size];
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
cend() const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
return &(*t_)[t_->size];
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
rbegin() noexcept ->
|
||||
reverse_iterator
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
rbegin() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
crbegin() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
rend() noexcept ->
|
||||
reverse_iterator
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
rend() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
crend() const noexcept ->
|
||||
const_reverse_iterator
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Capacity
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
bool
|
||||
object::
|
||||
empty() const noexcept
|
||||
{
|
||||
return t_->size == 0;
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
size() const noexcept ->
|
||||
std::size_t
|
||||
{
|
||||
return t_->size;
|
||||
}
|
||||
|
||||
constexpr
|
||||
std::size_t
|
||||
object::
|
||||
max_size() noexcept
|
||||
{
|
||||
// max_size depends on the address model
|
||||
using min = std::integral_constant<std::size_t,
|
||||
(std::size_t(-1) - sizeof(table)) /
|
||||
(sizeof(key_value_pair) + sizeof(index_t))>;
|
||||
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
|
||||
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
capacity() const noexcept ->
|
||||
std::size_t
|
||||
{
|
||||
return t_->capacity;
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
reserve(std::size_t new_capacity)
|
||||
{
|
||||
if( new_capacity <= capacity() )
|
||||
return;
|
||||
table* const old_table = reserve_impl(new_capacity);
|
||||
table::deallocate( old_table, sp_ );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Lookup
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
auto
|
||||
object::
|
||||
at(string_view key) & ->
|
||||
value&
|
||||
{
|
||||
auto const& self = *this;
|
||||
return const_cast< value& >( self.at(key) );
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
at(string_view key) && ->
|
||||
value&&
|
||||
{
|
||||
return std::move( at(key) );
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
at(string_view key) const& ->
|
||||
value const&
|
||||
{
|
||||
auto it = find(key);
|
||||
if(it == end())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::out_of_range, &loc );
|
||||
}
|
||||
return it->value();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class P, class>
|
||||
auto
|
||||
object::
|
||||
insert(P&& p) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
key_value_pair v(
|
||||
std::forward<P>(p), sp_);
|
||||
return emplace_impl( v.key(), pilfer(v) );
|
||||
}
|
||||
|
||||
template<class M>
|
||||
auto
|
||||
object::
|
||||
insert_or_assign(
|
||||
string_view key, M&& m) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
std::pair<iterator, bool> result = emplace_impl(
|
||||
key, key, static_cast<M&&>(m) );
|
||||
if( !result.second )
|
||||
{
|
||||
value(static_cast<M>(m), sp_).swap(
|
||||
result.first->value());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
auto
|
||||
object::
|
||||
emplace(
|
||||
string_view key,
|
||||
Arg&& arg) ->
|
||||
std::pair<iterator, bool>
|
||||
{
|
||||
return emplace_impl( key, key, static_cast<Arg&&>(arg) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// (private)
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
object::
|
||||
construct(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::size_t min_capacity,
|
||||
std::input_iterator_tag)
|
||||
{
|
||||
reserve(min_capacity);
|
||||
revert_construct r(*this);
|
||||
while(first != last)
|
||||
{
|
||||
insert(*first);
|
||||
++first;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
object::
|
||||
construct(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::size_t min_capacity,
|
||||
std::forward_iterator_tag)
|
||||
{
|
||||
auto n = static_cast<
|
||||
std::size_t>(std::distance(
|
||||
first, last));
|
||||
if( n < min_capacity)
|
||||
n = min_capacity;
|
||||
reserve(n);
|
||||
revert_construct r(*this);
|
||||
while(first != last)
|
||||
{
|
||||
insert(*first);
|
||||
++first;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
object::
|
||||
insert(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::input_iterator_tag)
|
||||
{
|
||||
// Since input iterators cannot be rewound,
|
||||
// we keep inserted elements on an exception.
|
||||
//
|
||||
while(first != last)
|
||||
{
|
||||
insert(*first);
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
object::
|
||||
insert(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::forward_iterator_tag)
|
||||
{
|
||||
auto const n =
|
||||
static_cast<std::size_t>(
|
||||
std::distance(first, last));
|
||||
auto const n0 = size();
|
||||
if(n > max_size() - n0)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::object_too_large, &loc );
|
||||
}
|
||||
revert_insert r( *this, n0 + n );
|
||||
while(first != last)
|
||||
{
|
||||
insert(*first);
|
||||
++first;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
template< class... Args >
|
||||
std::pair<object::iterator, bool>
|
||||
object::
|
||||
emplace_impl( string_view key, Args&& ... args )
|
||||
{
|
||||
std::pair<iterator, std::size_t> search_result(nullptr, 0);
|
||||
if( !empty() )
|
||||
{
|
||||
search_result = detail::find_in_object(*this, key);
|
||||
if( search_result.first )
|
||||
return { search_result.first, false };
|
||||
}
|
||||
|
||||
// we create the new value before reserving, in case it is a reference to
|
||||
// a subobject of the current object
|
||||
key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
|
||||
// the key might get deallocated too
|
||||
key = kv.key();
|
||||
|
||||
std::size_t const old_capacity = capacity();
|
||||
reserve(size() + 1);
|
||||
if( (empty() && capacity() > detail::small_object_size_)
|
||||
|| (capacity() != old_capacity) )
|
||||
search_result.second = detail::digest(
|
||||
key.begin(), key.end(), t_->salt);
|
||||
|
||||
BOOST_ASSERT(
|
||||
t_->is_small() ||
|
||||
(search_result.second ==
|
||||
detail::digest(key.begin(), key.end(), t_->salt)) );
|
||||
|
||||
return { insert_impl(pilfer(kv), search_result.second), true };
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
unchecked_object::
|
||||
~unchecked_object()
|
||||
{
|
||||
if(! data_)
|
||||
return;
|
||||
if(sp_.is_not_shared_and_deallocate_is_trivial())
|
||||
return;
|
||||
value* p = data_;
|
||||
while(size_--)
|
||||
{
|
||||
p[0].~value();
|
||||
p[1].~value();
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+897
@@ -0,0 +1,897 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_OBJECT_IPP
|
||||
#define BOOST_JSON_IMPL_OBJECT_IPP
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/detail/digest.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
template<class CharRange>
|
||||
std::pair<key_value_pair*, std::size_t>
|
||||
find_in_object(
|
||||
object const& obj,
|
||||
CharRange key) noexcept
|
||||
{
|
||||
BOOST_ASSERT(obj.t_->capacity > 0);
|
||||
if(obj.t_->is_small())
|
||||
{
|
||||
auto it = &(*obj.t_)[0];
|
||||
auto const last =
|
||||
&(*obj.t_)[obj.t_->size];
|
||||
for(;it != last; ++it)
|
||||
if( key == it->key() )
|
||||
return { it, 0 };
|
||||
return { nullptr, 0 };
|
||||
}
|
||||
std::pair<
|
||||
key_value_pair*,
|
||||
std::size_t> result;
|
||||
BOOST_ASSERT(obj.t_->salt != 0);
|
||||
result.second = detail::digest(key.begin(), key.end(), obj.t_->salt);
|
||||
auto i = obj.t_->bucket(
|
||||
result.second);
|
||||
while(i != object::null_index_)
|
||||
{
|
||||
auto& v = (*obj.t_)[i];
|
||||
if( key == v.key() )
|
||||
{
|
||||
result.first = &v;
|
||||
return result;
|
||||
}
|
||||
i = access::next(v);
|
||||
}
|
||||
result.first = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template
|
||||
std::pair<key_value_pair*, std::size_t>
|
||||
find_in_object<string_view>(
|
||||
object const& obj,
|
||||
string_view key) noexcept;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
constexpr object::table::table() = default;
|
||||
|
||||
// empty objects point here
|
||||
BOOST_JSON_REQUIRE_CONST_INIT
|
||||
object::table object::empty_;
|
||||
|
||||
std::size_t
|
||||
object::table::
|
||||
digest(string_view key) const noexcept
|
||||
{
|
||||
BOOST_ASSERT(salt != 0);
|
||||
return detail::digest(
|
||||
key.begin(), key.end(), salt);
|
||||
}
|
||||
|
||||
auto
|
||||
object::table::
|
||||
bucket(std::size_t hash) noexcept ->
|
||||
index_t&
|
||||
{
|
||||
return reinterpret_cast<
|
||||
index_t*>(&(*this)[capacity])[
|
||||
hash % capacity];
|
||||
}
|
||||
|
||||
auto
|
||||
object::table::
|
||||
bucket(string_view key) noexcept ->
|
||||
index_t&
|
||||
{
|
||||
return bucket(digest(key));
|
||||
}
|
||||
|
||||
void
|
||||
object::table::
|
||||
clear() noexcept
|
||||
{
|
||||
BOOST_ASSERT(! is_small());
|
||||
// initialize buckets
|
||||
std::memset(
|
||||
reinterpret_cast<index_t*>(
|
||||
&(*this)[capacity]),
|
||||
0xff, // null_index_
|
||||
capacity * sizeof(index_t));
|
||||
}
|
||||
|
||||
object::table*
|
||||
object::table::
|
||||
allocate(
|
||||
std::size_t capacity,
|
||||
std::uintptr_t salt,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(
|
||||
alignof(key_value_pair) >=
|
||||
alignof(index_t));
|
||||
BOOST_ASSERT(capacity > 0);
|
||||
BOOST_ASSERT(capacity <= max_size());
|
||||
table* p;
|
||||
if(capacity <= detail::small_object_size_)
|
||||
{
|
||||
p = reinterpret_cast<
|
||||
table*>(sp->allocate(
|
||||
sizeof(table) + capacity *
|
||||
sizeof(key_value_pair)));
|
||||
p->capacity = static_cast<
|
||||
std::uint32_t>(capacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = reinterpret_cast<
|
||||
table*>(sp->allocate(
|
||||
sizeof(table) + capacity * (
|
||||
sizeof(key_value_pair) +
|
||||
sizeof(index_t))));
|
||||
p->capacity = static_cast<
|
||||
std::uint32_t>(capacity);
|
||||
p->clear();
|
||||
}
|
||||
if(salt)
|
||||
{
|
||||
p->salt = salt;
|
||||
}
|
||||
else
|
||||
{
|
||||
// VFALCO This would be better if it
|
||||
// was random, but maybe this
|
||||
// is good enough.
|
||||
p->salt = reinterpret_cast<
|
||||
std::uintptr_t>(p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
object::
|
||||
revert_construct::
|
||||
destroy() noexcept
|
||||
{
|
||||
obj_->destroy();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
object::
|
||||
revert_insert::
|
||||
destroy() noexcept
|
||||
{
|
||||
obj_->destroy(
|
||||
&(*obj_->t_)[size_],
|
||||
obj_->end());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Construction
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
object::
|
||||
object(detail::unchecked_object&& uo)
|
||||
: sp_(uo.storage())
|
||||
{
|
||||
if(uo.size() == 0)
|
||||
{
|
||||
t_ = &empty_;
|
||||
return;
|
||||
}
|
||||
// should already be checked
|
||||
BOOST_ASSERT(
|
||||
uo.size() <= max_size());
|
||||
t_ = table::allocate(
|
||||
uo.size(), 0, sp_);
|
||||
|
||||
// insert all elements, keeping
|
||||
// the last of any duplicate keys.
|
||||
auto dest = begin();
|
||||
auto src = uo.release();
|
||||
auto const end = src + 2 * uo.size();
|
||||
if(t_->is_small())
|
||||
{
|
||||
t_->size = 0;
|
||||
while(src != end)
|
||||
{
|
||||
access::construct_key_value_pair(
|
||||
dest, pilfer(src[0]), pilfer(src[1]));
|
||||
src += 2;
|
||||
auto result = detail::find_in_object(*this, dest->key());
|
||||
if(! result.first)
|
||||
{
|
||||
++dest;
|
||||
++t_->size;
|
||||
continue;
|
||||
}
|
||||
// handle duplicate
|
||||
auto& v = *result.first;
|
||||
// don't bother to check if
|
||||
// storage deallocate is trivial
|
||||
v.~key_value_pair();
|
||||
// trivial relocate
|
||||
std::memcpy(
|
||||
static_cast<void*>(&v),
|
||||
dest, sizeof(v));
|
||||
}
|
||||
return;
|
||||
}
|
||||
while(src != end)
|
||||
{
|
||||
access::construct_key_value_pair(
|
||||
dest, pilfer(src[0]), pilfer(src[1]));
|
||||
src += 2;
|
||||
auto& head = t_->bucket(dest->key());
|
||||
auto i = head;
|
||||
for(;;)
|
||||
{
|
||||
if(i == null_index_)
|
||||
{
|
||||
// end of bucket
|
||||
access::next(
|
||||
*dest) = head;
|
||||
head = static_cast<index_t>(
|
||||
dest - begin());
|
||||
++dest;
|
||||
break;
|
||||
}
|
||||
auto& v = (*t_)[i];
|
||||
if(v.key() != dest->key())
|
||||
{
|
||||
i = access::next(v);
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle duplicate
|
||||
access::next(*dest) =
|
||||
access::next(v);
|
||||
// don't bother to check if
|
||||
// storage deallocate is trivial
|
||||
v.~key_value_pair();
|
||||
// trivial relocate
|
||||
std::memcpy(
|
||||
static_cast<void*>(&v),
|
||||
dest, sizeof(v));
|
||||
break;
|
||||
}
|
||||
}
|
||||
t_->size = static_cast<
|
||||
index_t>(dest - begin());
|
||||
}
|
||||
|
||||
object::
|
||||
~object() noexcept
|
||||
{
|
||||
if(sp_.is_not_shared_and_deallocate_is_trivial())
|
||||
return;
|
||||
if(t_->capacity == 0)
|
||||
return;
|
||||
destroy();
|
||||
}
|
||||
|
||||
object::
|
||||
object(
|
||||
std::size_t min_capacity,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, t_(&empty_)
|
||||
{
|
||||
reserve(min_capacity);
|
||||
}
|
||||
|
||||
object::
|
||||
object(object&& other) noexcept
|
||||
: sp_(other.sp_)
|
||||
, t_(detail::exchange(
|
||||
other.t_, &empty_))
|
||||
{
|
||||
}
|
||||
|
||||
object::
|
||||
object(
|
||||
object&& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
if(*sp_ == *other.sp_)
|
||||
{
|
||||
t_ = detail::exchange(
|
||||
other.t_, &empty_);
|
||||
return;
|
||||
}
|
||||
|
||||
t_ = &empty_;
|
||||
object(other, sp_).swap(*this);
|
||||
}
|
||||
|
||||
object::
|
||||
object(
|
||||
object const& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, t_(&empty_)
|
||||
{
|
||||
reserve(other.size());
|
||||
revert_construct r(*this);
|
||||
if(t_->is_small())
|
||||
{
|
||||
for(auto const& v : other)
|
||||
{
|
||||
::new(end())
|
||||
key_value_pair(v, sp_);
|
||||
++t_->size;
|
||||
}
|
||||
r.commit();
|
||||
return;
|
||||
}
|
||||
for(auto const& v : other)
|
||||
{
|
||||
// skip duplicate checking
|
||||
auto& head =
|
||||
t_->bucket(v.key());
|
||||
auto pv = ::new(end())
|
||||
key_value_pair(v, sp_);
|
||||
access::next(*pv) = head;
|
||||
head = t_->size;
|
||||
++t_->size;
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
object::
|
||||
object(
|
||||
std::initializer_list<std::pair<
|
||||
string_view, value_ref>> init,
|
||||
std::size_t min_capacity,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, t_(&empty_)
|
||||
{
|
||||
if( min_capacity < init.size())
|
||||
min_capacity = init.size();
|
||||
reserve(min_capacity);
|
||||
revert_construct r(*this);
|
||||
insert(init);
|
||||
r.commit();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Assignment
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
object&
|
||||
object::
|
||||
operator=(object const& other)
|
||||
{
|
||||
object tmp(other, sp_);
|
||||
this->~object();
|
||||
::new(this) object(pilfer(tmp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
object&
|
||||
object::
|
||||
operator=(object&& other)
|
||||
{
|
||||
object tmp(std::move(other), sp_);
|
||||
this->~object();
|
||||
::new(this) object(pilfer(tmp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
object&
|
||||
object::
|
||||
operator=(
|
||||
std::initializer_list<std::pair<
|
||||
string_view, value_ref>> init)
|
||||
{
|
||||
object tmp(init, sp_);
|
||||
this->~object();
|
||||
::new(this) object(pilfer(tmp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Modifiers
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
object::
|
||||
clear() noexcept
|
||||
{
|
||||
if(empty())
|
||||
return;
|
||||
if(! sp_.is_not_shared_and_deallocate_is_trivial())
|
||||
destroy(begin(), end());
|
||||
if(! t_->is_small())
|
||||
t_->clear();
|
||||
t_->size = 0;
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
insert(
|
||||
std::initializer_list<std::pair<
|
||||
string_view, value_ref>> init)
|
||||
{
|
||||
auto const n0 = size();
|
||||
if(init.size() > max_size() - n0)
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::object_too_large, &loc );
|
||||
}
|
||||
revert_insert r( *this, n0 + init.size() );
|
||||
if(t_->is_small())
|
||||
{
|
||||
for(auto& iv : init)
|
||||
{
|
||||
auto result =
|
||||
detail::find_in_object(*this, iv.first);
|
||||
if(result.first)
|
||||
{
|
||||
// ignore duplicate
|
||||
continue;
|
||||
}
|
||||
::new(end()) key_value_pair(
|
||||
iv.first,
|
||||
iv.second.make_value(sp_));
|
||||
++t_->size;
|
||||
}
|
||||
r.commit();
|
||||
return;
|
||||
}
|
||||
for(auto& iv : init)
|
||||
{
|
||||
auto& head = t_->bucket(iv.first);
|
||||
auto i = head;
|
||||
for(;;)
|
||||
{
|
||||
if(i == null_index_)
|
||||
{
|
||||
// VFALCO value_ref should construct
|
||||
// a key_value_pair using placement
|
||||
auto& v = *::new(end())
|
||||
key_value_pair(
|
||||
iv.first,
|
||||
iv.second.make_value(sp_));
|
||||
access::next(v) = head;
|
||||
head = static_cast<index_t>(
|
||||
t_->size);
|
||||
++t_->size;
|
||||
break;
|
||||
}
|
||||
auto& v = (*t_)[i];
|
||||
if(v.key() == iv.first)
|
||||
{
|
||||
// ignore duplicate
|
||||
break;
|
||||
}
|
||||
i = access::next(v);
|
||||
}
|
||||
}
|
||||
r.commit();
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
erase(const_iterator pos) noexcept ->
|
||||
iterator
|
||||
{
|
||||
return do_erase(pos,
|
||||
[this](iterator p) {
|
||||
// the casts silence warnings
|
||||
std::memcpy(
|
||||
static_cast<void*>(p),
|
||||
static_cast<void const*>(end()),
|
||||
sizeof(*p));
|
||||
},
|
||||
[this](iterator p) {
|
||||
reindex_relocate(end(), p);
|
||||
});
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
erase(string_view key) noexcept ->
|
||||
std::size_t
|
||||
{
|
||||
auto it = find(key);
|
||||
if(it == end())
|
||||
return 0;
|
||||
erase(it);
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
stable_erase(const_iterator pos) noexcept ->
|
||||
iterator
|
||||
{
|
||||
return do_erase(pos,
|
||||
[this](iterator p) {
|
||||
// the casts silence warnings
|
||||
std::memmove(
|
||||
static_cast<void*>(p),
|
||||
static_cast<void const*>(p + 1),
|
||||
sizeof(*p) * (end() - p));
|
||||
},
|
||||
[this](iterator p) {
|
||||
for (; p != end(); ++p)
|
||||
{
|
||||
reindex_relocate(p + 1, p);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
stable_erase(string_view key) noexcept ->
|
||||
std::size_t
|
||||
{
|
||||
auto it = find(key);
|
||||
if(it == end())
|
||||
return 0;
|
||||
stable_erase(it);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
swap(object& other)
|
||||
{
|
||||
if(*sp_ == *other.sp_)
|
||||
{
|
||||
t_ = detail::exchange(
|
||||
other.t_, t_);
|
||||
return;
|
||||
}
|
||||
object temp1(
|
||||
std::move(*this),
|
||||
other.storage());
|
||||
object temp2(
|
||||
std::move(other),
|
||||
this->storage());
|
||||
other.~object();
|
||||
::new(&other) object(pilfer(temp1));
|
||||
this->~object();
|
||||
::new(this) object(pilfer(temp2));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Lookup
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
auto
|
||||
object::
|
||||
operator[](string_view key) ->
|
||||
value&
|
||||
{
|
||||
auto const result =
|
||||
emplace(key, nullptr);
|
||||
return result.first->value();
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
count(string_view key) const noexcept ->
|
||||
std::size_t
|
||||
{
|
||||
if(find(key) == end())
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
find(string_view key) noexcept ->
|
||||
iterator
|
||||
{
|
||||
if(empty())
|
||||
return end();
|
||||
auto const p =
|
||||
detail::find_in_object(*this, key).first;
|
||||
if(p)
|
||||
return p;
|
||||
return end();
|
||||
}
|
||||
|
||||
auto
|
||||
object::
|
||||
find(string_view key) const noexcept ->
|
||||
const_iterator
|
||||
{
|
||||
if(empty())
|
||||
return end();
|
||||
auto const p =
|
||||
detail::find_in_object(*this, key).first;
|
||||
if(p)
|
||||
return p;
|
||||
return end();
|
||||
}
|
||||
|
||||
bool
|
||||
object::
|
||||
contains(
|
||||
string_view key) const noexcept
|
||||
{
|
||||
if(empty())
|
||||
return false;
|
||||
return detail::find_in_object(*this, key).first
|
||||
!= nullptr;
|
||||
}
|
||||
|
||||
value const*
|
||||
object::
|
||||
if_contains(
|
||||
string_view key) const noexcept
|
||||
{
|
||||
auto const it = find(key);
|
||||
if(it != end())
|
||||
return &it->value();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
value*
|
||||
object::
|
||||
if_contains(
|
||||
string_view key) noexcept
|
||||
{
|
||||
auto const it = find(key);
|
||||
if(it != end())
|
||||
return &it->value();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// (private)
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
key_value_pair*
|
||||
object::
|
||||
insert_impl(
|
||||
pilfered<key_value_pair> p,
|
||||
std::size_t hash)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
capacity() > size());
|
||||
if(t_->is_small())
|
||||
{
|
||||
auto const pv = ::new(end())
|
||||
key_value_pair(p);
|
||||
++t_->size;
|
||||
return pv;
|
||||
}
|
||||
auto& head =
|
||||
t_->bucket(hash);
|
||||
auto const pv = ::new(end())
|
||||
key_value_pair(p);
|
||||
access::next(*pv) = head;
|
||||
head = t_->size;
|
||||
++t_->size;
|
||||
return pv;
|
||||
}
|
||||
|
||||
// allocate new table, copy elements there, and rehash them
|
||||
object::table*
|
||||
object::
|
||||
reserve_impl(std::size_t new_capacity)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
new_capacity > t_->capacity);
|
||||
auto t = table::allocate(
|
||||
growth(new_capacity),
|
||||
t_->salt, sp_);
|
||||
if(! empty())
|
||||
std::memcpy(
|
||||
static_cast<
|
||||
void*>(&(*t)[0]),
|
||||
begin(),
|
||||
size() * sizeof(
|
||||
key_value_pair));
|
||||
t->size = t_->size;
|
||||
std::swap(t_, t);
|
||||
|
||||
if(! t_->is_small())
|
||||
{
|
||||
// rebuild hash table,
|
||||
// without dup checks
|
||||
auto p = end();
|
||||
index_t i = t_->size;
|
||||
while(i-- > 0)
|
||||
{
|
||||
--p;
|
||||
auto& head =
|
||||
t_->bucket(p->key());
|
||||
access::next(*p) = head;
|
||||
head = i;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
bool
|
||||
object::
|
||||
equal(object const& other) const noexcept
|
||||
{
|
||||
if(size() != other.size())
|
||||
return false;
|
||||
auto const end_ = other.end();
|
||||
for(auto e : *this)
|
||||
{
|
||||
auto it = other.find(e.key());
|
||||
if(it == end_)
|
||||
return false;
|
||||
if(it->value() != e.value())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
object::
|
||||
growth(
|
||||
std::size_t new_size) const
|
||||
{
|
||||
if(new_size > max_size())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::object_too_large, &loc );
|
||||
}
|
||||
std::size_t const old = capacity();
|
||||
if(old > max_size() - old / 2)
|
||||
return new_size;
|
||||
std::size_t const g =
|
||||
old + old / 2; // 1.5x
|
||||
if(g < new_size)
|
||||
return new_size;
|
||||
return g;
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
remove(
|
||||
index_t& head,
|
||||
key_value_pair& v) noexcept
|
||||
{
|
||||
BOOST_ASSERT(! t_->is_small());
|
||||
auto const i = static_cast<
|
||||
index_t>(&v - begin());
|
||||
if(head == i)
|
||||
{
|
||||
head = access::next(v);
|
||||
return;
|
||||
}
|
||||
auto* pn =
|
||||
&access::next((*t_)[head]);
|
||||
while(*pn != i)
|
||||
pn = &access::next((*t_)[*pn]);
|
||||
*pn = access::next(v);
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
destroy() noexcept
|
||||
{
|
||||
BOOST_ASSERT(t_->capacity > 0);
|
||||
BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial());
|
||||
destroy(begin(), end());
|
||||
table::deallocate(t_, sp_);
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
destroy(
|
||||
key_value_pair* first,
|
||||
key_value_pair* last) noexcept
|
||||
{
|
||||
BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial());
|
||||
while(last != first)
|
||||
(--last)->~key_value_pair();
|
||||
}
|
||||
|
||||
template<class FS, class FB>
|
||||
auto
|
||||
object::
|
||||
do_erase(
|
||||
const_iterator pos,
|
||||
FS small_reloc,
|
||||
FB big_reloc) noexcept
|
||||
-> iterator
|
||||
{
|
||||
auto p = begin() + (pos - begin());
|
||||
if(t_->is_small())
|
||||
{
|
||||
p->~value_type();
|
||||
--t_->size;
|
||||
if(p != end())
|
||||
{
|
||||
small_reloc(p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
remove(t_->bucket(p->key()), *p);
|
||||
p->~value_type();
|
||||
--t_->size;
|
||||
if(p != end())
|
||||
{
|
||||
big_reloc(p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
object::
|
||||
reindex_relocate(
|
||||
key_value_pair* src,
|
||||
key_value_pair* dst) noexcept
|
||||
{
|
||||
BOOST_ASSERT(! t_->is_small());
|
||||
auto& head = t_->bucket(src->key());
|
||||
remove(head, *src);
|
||||
// the casts silence warnings
|
||||
std::memcpy(
|
||||
static_cast<void*>(dst),
|
||||
static_cast<void const*>(src),
|
||||
sizeof(*dst));
|
||||
access::next(*dst) = head;
|
||||
head = static_cast<
|
||||
index_t>(dst - begin());
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// std::hash specialization
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
std::size_t
|
||||
std::hash<::boost::json::object>::operator()(
|
||||
::boost::json::object const& jo) const noexcept
|
||||
{
|
||||
return ::boost::hash< ::boost::json::object >()( jo );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
|
||||
#endif
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_PARSE_IPP
|
||||
#define BOOST_JSON_IMPL_PARSE_IPP
|
||||
|
||||
#include <boost/json/parse.hpp>
|
||||
#include <boost/json/parser.hpp>
|
||||
#include <boost/json/detail/except.hpp>
|
||||
|
||||
#include <istream>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
value
|
||||
parse(
|
||||
string_view s,
|
||||
error_code& ec,
|
||||
storage_ptr sp,
|
||||
const parse_options& opt)
|
||||
{
|
||||
unsigned char temp[
|
||||
BOOST_JSON_STACK_BUFFER_SIZE];
|
||||
parser p(storage_ptr(), opt, temp);
|
||||
p.reset(std::move(sp));
|
||||
p.write(s, ec);
|
||||
if(ec)
|
||||
return nullptr;
|
||||
return p.release();
|
||||
}
|
||||
|
||||
value
|
||||
parse(
|
||||
string_view s,
|
||||
std::error_code& ec,
|
||||
storage_ptr sp,
|
||||
parse_options const& opt)
|
||||
{
|
||||
error_code jec;
|
||||
value result = parse(s, jec, std::move(sp), opt);
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
value
|
||||
parse(
|
||||
string_view s,
|
||||
storage_ptr sp,
|
||||
const parse_options& opt)
|
||||
{
|
||||
error_code ec;
|
||||
auto jv = parse(
|
||||
s, ec, std::move(sp), opt);
|
||||
if(ec)
|
||||
detail::throw_system_error( ec );
|
||||
return jv;
|
||||
}
|
||||
|
||||
value
|
||||
parse(
|
||||
std::istream& is,
|
||||
error_code& ec,
|
||||
storage_ptr sp,
|
||||
parse_options const& opt)
|
||||
{
|
||||
unsigned char parser_buffer[BOOST_JSON_STACK_BUFFER_SIZE / 2];
|
||||
stream_parser p(storage_ptr(), opt, parser_buffer);
|
||||
p.reset(std::move(sp));
|
||||
|
||||
char read_buffer[BOOST_JSON_STACK_BUFFER_SIZE / 2];
|
||||
do
|
||||
{
|
||||
if( is.eof() )
|
||||
{
|
||||
p.finish(ec);
|
||||
break;
|
||||
}
|
||||
|
||||
if( !is )
|
||||
{
|
||||
BOOST_JSON_FAIL( ec, error::input_error );
|
||||
break;
|
||||
}
|
||||
|
||||
is.read(read_buffer, sizeof(read_buffer));
|
||||
auto const consumed = is.gcount();
|
||||
|
||||
p.write( read_buffer, static_cast<std::size_t>(consumed), ec );
|
||||
}
|
||||
while( !ec.failed() );
|
||||
|
||||
if( ec.failed() )
|
||||
return nullptr;
|
||||
|
||||
return p.release();
|
||||
}
|
||||
|
||||
value
|
||||
parse(
|
||||
std::istream& is,
|
||||
std::error_code& ec,
|
||||
storage_ptr sp,
|
||||
parse_options const& opt)
|
||||
{
|
||||
error_code jec;
|
||||
value result = parse(is, jec, std::move(sp), opt);
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
value
|
||||
parse(
|
||||
std::istream& is,
|
||||
storage_ptr sp,
|
||||
parse_options const& opt)
|
||||
{
|
||||
error_code ec;
|
||||
auto jv = parse(
|
||||
is, ec, std::move(sp), opt);
|
||||
if(ec)
|
||||
detail::throw_system_error( ec );
|
||||
return jv;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_PARSE_INTO_HPP
|
||||
#define BOOST_JSON_IMPL_PARSE_INTO_HPP
|
||||
|
||||
#include <boost/json/basic_parser_impl.hpp>
|
||||
#include <boost/json/error.hpp>
|
||||
#include <istream>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
string_view sv,
|
||||
error_code& ec,
|
||||
parse_options const& opt )
|
||||
{
|
||||
parser_for<V> p( opt, &v );
|
||||
|
||||
std::size_t n = p.write_some( false, sv.data(), sv.size(), ec );
|
||||
|
||||
if( !ec && n < sv.size() )
|
||||
{
|
||||
BOOST_JSON_FAIL( ec, error::extra_data );
|
||||
}
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
string_view sv,
|
||||
std::error_code& ec,
|
||||
parse_options const& opt )
|
||||
{
|
||||
error_code jec;
|
||||
parse_into(v, sv, jec, opt);
|
||||
ec = jec;
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
string_view sv,
|
||||
parse_options const& opt )
|
||||
{
|
||||
error_code ec;
|
||||
parse_into(v, sv, ec, opt);
|
||||
if( ec.failed() )
|
||||
detail::throw_system_error( ec );
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
std::istream& is,
|
||||
error_code& ec,
|
||||
parse_options const& opt )
|
||||
{
|
||||
parser_for<V> p( opt, &v );
|
||||
|
||||
char read_buffer[BOOST_JSON_STACK_BUFFER_SIZE];
|
||||
do
|
||||
{
|
||||
if( is.eof() )
|
||||
{
|
||||
p.write_some(false, nullptr, 0, ec);
|
||||
break;
|
||||
}
|
||||
|
||||
if( !is )
|
||||
{
|
||||
BOOST_JSON_FAIL( ec, error::input_error );
|
||||
break;
|
||||
}
|
||||
|
||||
is.read(read_buffer, sizeof(read_buffer));
|
||||
std::size_t const consumed = static_cast<std::size_t>( is.gcount() );
|
||||
|
||||
std::size_t const n = p.write_some( true, read_buffer, consumed, ec );
|
||||
if( !ec.failed() && n < consumed )
|
||||
{
|
||||
BOOST_JSON_FAIL( ec, error::extra_data );
|
||||
}
|
||||
}
|
||||
while( !ec.failed() );
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
std::istream& is,
|
||||
std::error_code& ec,
|
||||
parse_options const& opt )
|
||||
{
|
||||
error_code jec;
|
||||
parse_into(v, is, jec, opt);
|
||||
ec = jec;
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
std::istream& is,
|
||||
parse_options const& opt )
|
||||
{
|
||||
error_code ec;
|
||||
parse_into(v, is, ec, opt);
|
||||
if( ec.failed() )
|
||||
detail::throw_system_error( ec );
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
|
||||
#endif
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_PARSER_IPP
|
||||
#define BOOST_JSON_IMPL_PARSER_IPP
|
||||
|
||||
#include <boost/json/parser.hpp>
|
||||
#include <boost/json/basic_parser_impl.hpp>
|
||||
#include <boost/json/error.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
parser::
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
unsigned char* buffer,
|
||||
std::size_t size) noexcept
|
||||
: p_(
|
||||
opt,
|
||||
std::move(sp),
|
||||
buffer,
|
||||
size)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
parser::
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt) noexcept
|
||||
: p_(
|
||||
opt,
|
||||
std::move(sp),
|
||||
nullptr,
|
||||
0)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void
|
||||
parser::
|
||||
reset(storage_ptr sp) noexcept
|
||||
{
|
||||
p_.reset();
|
||||
p_.handler().st.reset(sp);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
false, data, size, ec);
|
||||
BOOST_ASSERT(ec || p_.done());
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
std::error_code& ec)
|
||||
{
|
||||
error_code jec;
|
||||
std::size_t const result = write_some(data, size, jec);
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size)
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = write_some(
|
||||
data, size, ec);
|
||||
if(ec)
|
||||
detail::throw_system_error( ec );
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = write_some(
|
||||
data, size, ec);
|
||||
if(! ec && n < size)
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::extra_data);
|
||||
p_.fail(ec);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
std::error_code& ec)
|
||||
{
|
||||
error_code jec;
|
||||
std::size_t const result = write(data, size, jec);
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size)
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = write(
|
||||
data, size, ec);
|
||||
if(ec)
|
||||
detail::throw_system_error( ec );
|
||||
return n;
|
||||
}
|
||||
|
||||
value
|
||||
parser::
|
||||
release()
|
||||
{
|
||||
if( ! p_.done())
|
||||
{
|
||||
// prevent undefined behavior
|
||||
if(! p_.last_error())
|
||||
{
|
||||
error_code ec;
|
||||
BOOST_JSON_FAIL(ec, error::incomplete);
|
||||
p_.fail(ec);
|
||||
}
|
||||
detail::throw_system_error(
|
||||
p_.last_error());
|
||||
}
|
||||
return p_.handler().st.release();
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+501
@@ -0,0 +1,501 @@
|
||||
//
|
||||
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_POINTER_IPP
|
||||
#define BOOST_JSON_IMPL_POINTER_IPP
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class pointer_token
|
||||
{
|
||||
public:
|
||||
class iterator;
|
||||
|
||||
pointer_token(
|
||||
string_view sv) noexcept
|
||||
: b_( sv.begin() + 1 )
|
||||
, e_( sv.end() )
|
||||
{
|
||||
BOOST_ASSERT( !sv.empty() );
|
||||
BOOST_ASSERT( *sv.data() == '/' );
|
||||
}
|
||||
|
||||
iterator begin() const noexcept;
|
||||
iterator end() const noexcept;
|
||||
|
||||
private:
|
||||
char const* b_;
|
||||
char const* e_;
|
||||
};
|
||||
|
||||
class pointer_token::iterator
|
||||
{
|
||||
public:
|
||||
using value_type = char;
|
||||
using reference = char;
|
||||
using pointer = value_type*;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
explicit iterator(char const* base) noexcept
|
||||
: base_(base)
|
||||
{
|
||||
}
|
||||
|
||||
char operator*() const noexcept
|
||||
{
|
||||
switch( char c = *base_ )
|
||||
{
|
||||
case '~':
|
||||
c = base_[1];
|
||||
if( '0' == c )
|
||||
return '~';
|
||||
BOOST_ASSERT('1' == c);
|
||||
return '/';
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
iterator& operator++() noexcept
|
||||
{
|
||||
if( '~' == *base_ )
|
||||
base_ += 2;
|
||||
else
|
||||
++base_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) noexcept
|
||||
{
|
||||
iterator result = *this;
|
||||
++(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
char const* base() const noexcept
|
||||
{
|
||||
return base_;
|
||||
}
|
||||
|
||||
private:
|
||||
char const* base_;
|
||||
};
|
||||
|
||||
bool operator==(pointer_token::iterator l, pointer_token::iterator r) noexcept
|
||||
{
|
||||
return l.base() == r.base();
|
||||
}
|
||||
|
||||
bool operator!=(pointer_token::iterator l, pointer_token::iterator r) noexcept
|
||||
{
|
||||
return l.base() != r.base();
|
||||
}
|
||||
|
||||
pointer_token::iterator pointer_token::begin() const noexcept
|
||||
{
|
||||
return iterator(b_);
|
||||
}
|
||||
|
||||
pointer_token::iterator pointer_token::end() const noexcept
|
||||
{
|
||||
return iterator(e_);
|
||||
}
|
||||
|
||||
bool operator==(pointer_token token, string_view sv) noexcept
|
||||
{
|
||||
auto t_b = token.begin();
|
||||
auto const t_e = token.end();
|
||||
auto s_b = sv.begin();
|
||||
auto const s_e = sv.end();
|
||||
while( s_b != s_e )
|
||||
{
|
||||
if( t_e == t_b )
|
||||
return false;
|
||||
if( *t_b != *s_b )
|
||||
return false;
|
||||
++t_b;
|
||||
++s_b;
|
||||
}
|
||||
return t_b == t_e;
|
||||
}
|
||||
|
||||
bool is_invalid_zero(
|
||||
char const* b,
|
||||
char const* e) noexcept
|
||||
{
|
||||
// in JSON Pointer only zero index can start character '0'
|
||||
if( *b != '0' )
|
||||
return false;
|
||||
|
||||
// if an index token starts with '0', then it should not have any more
|
||||
// characters: either the string should end, or new token should start
|
||||
++b;
|
||||
if( b == e )
|
||||
return false;
|
||||
|
||||
BOOST_ASSERT( *b != '/' );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_past_the_end_token(
|
||||
char const* b,
|
||||
char const* e) noexcept
|
||||
{
|
||||
if( *b != '-' )
|
||||
return false;
|
||||
|
||||
++b;
|
||||
BOOST_ASSERT( (b == e) || (*b != '/') );
|
||||
return b == e;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parse_number_token(
|
||||
string_view sv,
|
||||
error_code& ec) noexcept
|
||||
{
|
||||
BOOST_ASSERT( !sv.empty() );
|
||||
|
||||
char const* b = sv.begin();
|
||||
BOOST_ASSERT( *b == '/' );
|
||||
|
||||
++b;
|
||||
char const* const e = sv.end();
|
||||
if( ( b == e )
|
||||
|| is_invalid_zero(b, e) )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::token_not_number);
|
||||
return {};
|
||||
}
|
||||
|
||||
if( is_past_the_end_token(b, e) )
|
||||
{
|
||||
++b;
|
||||
BOOST_JSON_FAIL(ec, error::past_the_end);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t result = 0;
|
||||
for( ; b != e; ++b )
|
||||
{
|
||||
char const c = *b;
|
||||
BOOST_ASSERT( c != '/' );
|
||||
|
||||
unsigned d = c - '0';
|
||||
if( d > 9 )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::token_not_number);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t new_result = result * 10 + d;
|
||||
if( new_result < result )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::token_overflow);
|
||||
return {};
|
||||
}
|
||||
|
||||
result = new_result;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string_view
|
||||
next_segment(
|
||||
string_view& sv,
|
||||
error_code& ec) noexcept
|
||||
{
|
||||
if( sv.empty() )
|
||||
return sv;
|
||||
|
||||
char const* const start = sv.begin();
|
||||
char const* b = start;
|
||||
if( *b++ != '/' )
|
||||
{
|
||||
BOOST_JSON_FAIL( ec, error::missing_slash );
|
||||
return {};
|
||||
}
|
||||
|
||||
char const* e = sv.end();
|
||||
for( ; b < e; ++b )
|
||||
{
|
||||
char const c = *b;
|
||||
if( '/' == c )
|
||||
break;
|
||||
|
||||
if( '~' == c )
|
||||
{
|
||||
if( ++b == e )
|
||||
{
|
||||
BOOST_JSON_FAIL( ec, error::invalid_escape );
|
||||
break;
|
||||
}
|
||||
|
||||
switch (*b)
|
||||
{
|
||||
case '0': // fall through
|
||||
case '1':
|
||||
// valid escape sequence
|
||||
continue;
|
||||
default: {
|
||||
BOOST_JSON_FAIL( ec, error::invalid_escape );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sv.remove_prefix( b - start );
|
||||
return string_view( start, b );
|
||||
}
|
||||
|
||||
value*
|
||||
if_contains_token(object const& obj, pointer_token token)
|
||||
{
|
||||
if( obj.empty() )
|
||||
return nullptr;
|
||||
|
||||
auto const it = detail::find_in_object(obj, token).first;
|
||||
if( !it )
|
||||
return nullptr;
|
||||
|
||||
return &it->value();
|
||||
}
|
||||
|
||||
template<
|
||||
class Value,
|
||||
class OnObject,
|
||||
class OnArray,
|
||||
class OnScalar >
|
||||
Value*
|
||||
walk_pointer(
|
||||
Value& jv,
|
||||
string_view sv,
|
||||
error_code& ec,
|
||||
OnObject on_object,
|
||||
OnArray on_array,
|
||||
OnScalar on_scalar)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
string_view segment = detail::next_segment( sv, ec );
|
||||
|
||||
Value* result = &jv;
|
||||
while( true )
|
||||
{
|
||||
if( ec.failed() )
|
||||
return nullptr;
|
||||
|
||||
if( !result )
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::not_found);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if( segment.empty() )
|
||||
break;
|
||||
|
||||
switch( result->kind() )
|
||||
{
|
||||
case kind::object: {
|
||||
auto& obj = result->get_object();
|
||||
|
||||
detail::pointer_token const token( segment );
|
||||
segment = detail::next_segment( sv, ec );
|
||||
|
||||
result = on_object( obj, token );
|
||||
break;
|
||||
}
|
||||
case kind::array: {
|
||||
auto const index = detail::parse_number_token( segment, ec );
|
||||
segment = detail::next_segment( sv, ec );
|
||||
|
||||
auto& arr = result->get_array();
|
||||
result = on_array( arr, index, ec );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( on_scalar( *result, segment ) )
|
||||
break;
|
||||
BOOST_JSON_FAIL( ec, error::value_is_scalar );
|
||||
}}
|
||||
}
|
||||
|
||||
BOOST_ASSERT( result );
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
value const&
|
||||
value::at_pointer(string_view ptr) const&
|
||||
{
|
||||
error_code ec;
|
||||
auto const found = find_pointer(ptr, ec);
|
||||
if( !found )
|
||||
detail::throw_system_error( ec );
|
||||
return *found;
|
||||
}
|
||||
|
||||
value const*
|
||||
value::find_pointer( string_view sv, error_code& ec ) const noexcept
|
||||
{
|
||||
return detail::walk_pointer(
|
||||
*this,
|
||||
sv,
|
||||
ec,
|
||||
[]( object const& obj, detail::pointer_token token )
|
||||
{
|
||||
return detail::if_contains_token(obj, token);
|
||||
},
|
||||
[]( array const& arr, std::size_t index, error_code& ec )
|
||||
-> value const*
|
||||
{
|
||||
if( ec )
|
||||
return nullptr;
|
||||
|
||||
return arr.if_contains(index);
|
||||
},
|
||||
[]( value const&, string_view)
|
||||
{
|
||||
return std::false_type();
|
||||
});
|
||||
}
|
||||
|
||||
value*
|
||||
value::find_pointer(string_view ptr, error_code& ec) noexcept
|
||||
{
|
||||
value const& self = *this;
|
||||
return const_cast<value*>(self.find_pointer(ptr, ec));
|
||||
}
|
||||
|
||||
value const*
|
||||
value::find_pointer(string_view ptr, std::error_code& ec) const noexcept
|
||||
{
|
||||
error_code jec;
|
||||
value const* result = find_pointer(ptr, jec);
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
value*
|
||||
value::find_pointer(string_view ptr, std::error_code& ec) noexcept
|
||||
{
|
||||
value const& self = *this;
|
||||
return const_cast<value*>(self.find_pointer(ptr, ec));
|
||||
}
|
||||
|
||||
value*
|
||||
value::set_at_pointer(
|
||||
string_view sv,
|
||||
value_ref ref,
|
||||
error_code& ec,
|
||||
set_pointer_options const& opts )
|
||||
{
|
||||
value* result = detail::walk_pointer(
|
||||
*this,
|
||||
sv,
|
||||
ec,
|
||||
[]( object& obj, detail::pointer_token token)
|
||||
{
|
||||
if( !obj.empty() )
|
||||
{
|
||||
key_value_pair* kv = detail::find_in_object( obj, token ).first;
|
||||
if( kv )
|
||||
return &kv->value();
|
||||
}
|
||||
|
||||
string key( token.begin(), token.end(), obj.storage() );
|
||||
return &obj.emplace( std::move(key), nullptr ).first->value();
|
||||
},
|
||||
[ &opts ]( array& arr, std::size_t index, error_code& ec ) -> value*
|
||||
{
|
||||
if( ec == error::past_the_end )
|
||||
index = arr.size();
|
||||
else if( ec.failed() )
|
||||
return nullptr;
|
||||
|
||||
if( index >= arr.size() )
|
||||
{
|
||||
std::size_t const n = index - arr.size();
|
||||
if( n >= opts.max_created_elements )
|
||||
return nullptr;
|
||||
|
||||
arr.resize( arr.size() + n + 1 );
|
||||
}
|
||||
|
||||
ec.clear();
|
||||
return arr.data() + index;
|
||||
},
|
||||
[ &opts ]( value& jv, string_view segment )
|
||||
{
|
||||
if( jv.is_null() || opts.replace_any_scalar )
|
||||
{
|
||||
if( opts.create_arrays )
|
||||
{
|
||||
error_code ec;
|
||||
detail::parse_number_token( segment, ec );
|
||||
if( !ec.failed() || ec == error::past_the_end )
|
||||
{
|
||||
jv = array( jv.storage() );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if( opts.create_objects )
|
||||
{
|
||||
jv = object( jv.storage() );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if( result )
|
||||
*result = ref.make_value( storage() );
|
||||
return result;
|
||||
}
|
||||
|
||||
value*
|
||||
value::set_at_pointer(
|
||||
string_view sv,
|
||||
value_ref ref,
|
||||
std::error_code& ec,
|
||||
set_pointer_options const& opts )
|
||||
{
|
||||
error_code jec;
|
||||
value* result = set_at_pointer( sv, ref, jec, opts );
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
value&
|
||||
value::set_at_pointer(
|
||||
string_view sv, value_ref ref, set_pointer_options const& opts )
|
||||
{
|
||||
error_code ec;
|
||||
value* result = set_at_pointer( sv, ref, ec, opts );
|
||||
if( !result )
|
||||
detail::throw_system_error( ec );
|
||||
return *result;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_JSON_IMPL_POINTER_IPP
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_SERIALIZE_IPP
|
||||
#define BOOST_JSON_IMPL_SERIALIZE_IPP
|
||||
|
||||
#include <boost/json/serialize.hpp>
|
||||
#include <boost/json/serializer.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace {
|
||||
|
||||
int serialize_xalloc = std::ios::xalloc();
|
||||
|
||||
enum class serialize_stream_flags : long
|
||||
{
|
||||
allow_infinity_and_nan = 1,
|
||||
};
|
||||
|
||||
std::underlying_type<serialize_stream_flags>::type
|
||||
to_bitmask( serialize_options const& opts )
|
||||
{
|
||||
using E = serialize_stream_flags;
|
||||
using I = std::underlying_type<E>::type;
|
||||
return (opts.allow_infinity_and_nan
|
||||
? static_cast<I>(E::allow_infinity_and_nan) : 0);
|
||||
}
|
||||
|
||||
serialize_options
|
||||
get_stream_flags( std::ostream& os )
|
||||
{
|
||||
auto const flags = os.iword(serialize_xalloc);
|
||||
|
||||
serialize_options opts;
|
||||
using E = serialize_stream_flags;
|
||||
using I = std::underlying_type<E>::type;
|
||||
opts.allow_infinity_and_nan =
|
||||
flags & static_cast<I>(E::allow_infinity_and_nan);
|
||||
return opts;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static
|
||||
void
|
||||
serialize_impl(
|
||||
std::string& s,
|
||||
serializer& sr)
|
||||
{
|
||||
// serialize to a small buffer to avoid
|
||||
// the first few allocations in std::string
|
||||
char buf[BOOST_JSON_STACK_BUFFER_SIZE];
|
||||
string_view sv;
|
||||
sv = sr.read(buf);
|
||||
if(sr.done())
|
||||
{
|
||||
// fast path
|
||||
s.append(
|
||||
sv.data(), sv.size());
|
||||
return;
|
||||
}
|
||||
std::size_t len = sv.size();
|
||||
s.reserve(len * 2);
|
||||
s.resize(s.capacity());
|
||||
BOOST_ASSERT(
|
||||
s.size() >= len * 2);
|
||||
std::memcpy(&s[0],
|
||||
sv.data(), sv.size());
|
||||
auto const lim =
|
||||
s.max_size() / 2;
|
||||
for(;;)
|
||||
{
|
||||
sv = sr.read(
|
||||
&s[0] + len,
|
||||
s.size() - len);
|
||||
len += sv.size();
|
||||
if(sr.done())
|
||||
break;
|
||||
// growth factor 2x
|
||||
if(s.size() < lim)
|
||||
s.resize(s.size() * 2);
|
||||
else
|
||||
s.resize(2 * lim);
|
||||
}
|
||||
s.resize(len);
|
||||
}
|
||||
|
||||
std::string
|
||||
serialize(
|
||||
value const& jv,
|
||||
serialize_options const& opts)
|
||||
{
|
||||
unsigned char buf[256];
|
||||
serializer sr(
|
||||
storage_ptr(),
|
||||
buf,
|
||||
sizeof(buf),
|
||||
opts);
|
||||
sr.reset(&jv);
|
||||
std::string s;
|
||||
serialize_impl(s, sr);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string
|
||||
serialize(
|
||||
array const& arr,
|
||||
serialize_options const& opts)
|
||||
{
|
||||
unsigned char buf[256];
|
||||
serializer sr(
|
||||
storage_ptr(),
|
||||
buf,
|
||||
sizeof(buf),
|
||||
opts);
|
||||
std::string s;
|
||||
sr.reset(&arr);
|
||||
serialize_impl(s, sr);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string
|
||||
serialize(
|
||||
object const& obj,
|
||||
serialize_options const& opts)
|
||||
{
|
||||
unsigned char buf[256];
|
||||
serializer sr(
|
||||
storage_ptr(),
|
||||
buf,
|
||||
sizeof(buf),
|
||||
opts);
|
||||
std::string s;
|
||||
sr.reset(&obj);
|
||||
serialize_impl(s, sr);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string
|
||||
serialize(
|
||||
string const& str,
|
||||
serialize_options const& opts)
|
||||
{
|
||||
return serialize( str.subview(), opts );
|
||||
}
|
||||
|
||||
// this is here for key_value_pair::key()
|
||||
std::string
|
||||
serialize(
|
||||
string_view sv,
|
||||
serialize_options const& opts)
|
||||
{
|
||||
unsigned char buf[256];
|
||||
serializer sr(
|
||||
storage_ptr(),
|
||||
buf,
|
||||
sizeof(buf),
|
||||
opts);
|
||||
std::string s;
|
||||
sr.reset(sv);
|
||||
serialize_impl(s, sr);
|
||||
return s;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
//[example_operator_lt__lt_
|
||||
// Serialize a value into an output stream
|
||||
|
||||
std::ostream&
|
||||
operator<<( std::ostream& os, value const& jv )
|
||||
{
|
||||
// Create a serializer
|
||||
serializer sr( get_stream_flags(os) );
|
||||
|
||||
// Set the serializer up for our value
|
||||
sr.reset( &jv );
|
||||
|
||||
// Loop until all output is produced.
|
||||
while( ! sr.done() )
|
||||
{
|
||||
// Use a local buffer to avoid allocation.
|
||||
char buf[ BOOST_JSON_STACK_BUFFER_SIZE ];
|
||||
|
||||
// Fill our buffer with serialized characters and write it to the output stream.
|
||||
os << sr.read( buf );
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
//]
|
||||
|
||||
static
|
||||
void
|
||||
to_ostream(
|
||||
std::ostream& os,
|
||||
serializer& sr)
|
||||
{
|
||||
while(! sr.done())
|
||||
{
|
||||
char buf[BOOST_JSON_STACK_BUFFER_SIZE];
|
||||
auto s = sr.read(buf);
|
||||
os.write(s.data(), s.size());
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(
|
||||
std::ostream& os,
|
||||
array const& arr)
|
||||
{
|
||||
serializer sr( get_stream_flags(os) );
|
||||
sr.reset(&arr);
|
||||
to_ostream(os, sr);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(
|
||||
std::ostream& os,
|
||||
object const& obj)
|
||||
{
|
||||
serializer sr( get_stream_flags(os) );
|
||||
sr.reset(&obj);
|
||||
to_ostream(os, sr);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(
|
||||
std::ostream& os,
|
||||
string const& str)
|
||||
{
|
||||
serializer sr( get_stream_flags(os) );
|
||||
sr.reset(&str);
|
||||
to_ostream(os, sr);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<( std::ostream& os, serialize_options const& opts )
|
||||
{
|
||||
os.iword(serialize_xalloc) = to_bitmask(opts);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+839
@@ -0,0 +1,839 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
|
||||
#define BOOST_JSON_IMPL_SERIALIZER_IPP
|
||||
|
||||
#include <boost/json/serializer.hpp>
|
||||
#include <boost/json/detail/format.hpp>
|
||||
#include <boost/json/detail/sse2.hpp>
|
||||
#include <ostream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
enum class serializer::state : char
|
||||
{
|
||||
nul1, nul2, nul3, nul4,
|
||||
tru1, tru2, tru3, tru4,
|
||||
fal1, fal2, fal3, fal4, fal5,
|
||||
str1, str2, str3, str4, esc1,
|
||||
utf1, utf2, utf3, utf4, utf5,
|
||||
num,
|
||||
arr1, arr2, arr3, arr4,
|
||||
obj1, obj2, obj3, obj4, obj5, obj6
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
serializer::
|
||||
serializer(
|
||||
storage_ptr sp,
|
||||
unsigned char* buf,
|
||||
std::size_t buf_size,
|
||||
serialize_options const& opts) noexcept
|
||||
: st_(
|
||||
std::move(sp),
|
||||
buf,
|
||||
buf_size)
|
||||
, opts_(opts)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
serializer::
|
||||
suspend(state st)
|
||||
{
|
||||
st_.push(st);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
serializer::
|
||||
suspend(
|
||||
state st,
|
||||
array::const_iterator it,
|
||||
array const* pa)
|
||||
{
|
||||
st_.push(pa);
|
||||
st_.push(it);
|
||||
st_.push(st);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
serializer::
|
||||
suspend(
|
||||
state st,
|
||||
object::const_iterator it,
|
||||
object const* po)
|
||||
{
|
||||
st_.push(po);
|
||||
st_.push(it);
|
||||
st_.push(st);
|
||||
return false;
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_null(stream& ss0)
|
||||
{
|
||||
local_stream ss(ss0);
|
||||
if(! StackEmpty && ! st_.empty())
|
||||
{
|
||||
state st;
|
||||
st_.pop(st);
|
||||
switch(st)
|
||||
{
|
||||
default:
|
||||
case state::nul1: goto do_nul1;
|
||||
case state::nul2: goto do_nul2;
|
||||
case state::nul3: goto do_nul3;
|
||||
case state::nul4: goto do_nul4;
|
||||
}
|
||||
}
|
||||
do_nul1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('n');
|
||||
else
|
||||
return suspend(state::nul1);
|
||||
do_nul2:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('u');
|
||||
else
|
||||
return suspend(state::nul2);
|
||||
do_nul3:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('l');
|
||||
else
|
||||
return suspend(state::nul3);
|
||||
do_nul4:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('l');
|
||||
else
|
||||
return suspend(state::nul4);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_true(stream& ss0)
|
||||
{
|
||||
local_stream ss(ss0);
|
||||
if(! StackEmpty && ! st_.empty())
|
||||
{
|
||||
state st;
|
||||
st_.pop(st);
|
||||
switch(st)
|
||||
{
|
||||
default:
|
||||
case state::tru1: goto do_tru1;
|
||||
case state::tru2: goto do_tru2;
|
||||
case state::tru3: goto do_tru3;
|
||||
case state::tru4: goto do_tru4;
|
||||
}
|
||||
}
|
||||
do_tru1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('t');
|
||||
else
|
||||
return suspend(state::tru1);
|
||||
do_tru2:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('r');
|
||||
else
|
||||
return suspend(state::tru2);
|
||||
do_tru3:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('u');
|
||||
else
|
||||
return suspend(state::tru3);
|
||||
do_tru4:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('e');
|
||||
else
|
||||
return suspend(state::tru4);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_false(stream& ss0)
|
||||
{
|
||||
local_stream ss(ss0);
|
||||
if(! StackEmpty && ! st_.empty())
|
||||
{
|
||||
state st;
|
||||
st_.pop(st);
|
||||
switch(st)
|
||||
{
|
||||
default:
|
||||
case state::fal1: goto do_fal1;
|
||||
case state::fal2: goto do_fal2;
|
||||
case state::fal3: goto do_fal3;
|
||||
case state::fal4: goto do_fal4;
|
||||
case state::fal5: goto do_fal5;
|
||||
}
|
||||
}
|
||||
do_fal1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('f');
|
||||
else
|
||||
return suspend(state::fal1);
|
||||
do_fal2:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('a');
|
||||
else
|
||||
return suspend(state::fal2);
|
||||
do_fal3:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('l');
|
||||
else
|
||||
return suspend(state::fal3);
|
||||
do_fal4:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('s');
|
||||
else
|
||||
return suspend(state::fal4);
|
||||
do_fal5:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('e');
|
||||
else
|
||||
return suspend(state::fal5);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_string(stream& ss0)
|
||||
{
|
||||
local_stream ss(ss0);
|
||||
local_const_stream cs(cs0_);
|
||||
if(! StackEmpty && ! st_.empty())
|
||||
{
|
||||
state st;
|
||||
st_.pop(st);
|
||||
switch(st)
|
||||
{
|
||||
default:
|
||||
case state::str1: goto do_str1;
|
||||
case state::str2: goto do_str2;
|
||||
case state::str3: goto do_str3;
|
||||
case state::str4: goto do_str4;
|
||||
case state::esc1: goto do_esc1;
|
||||
case state::utf1: goto do_utf1;
|
||||
case state::utf2: goto do_utf2;
|
||||
case state::utf3: goto do_utf3;
|
||||
case state::utf4: goto do_utf4;
|
||||
case state::utf5: goto do_utf5;
|
||||
}
|
||||
}
|
||||
static constexpr char hex[] = "0123456789abcdef";
|
||||
static constexpr char esc[] =
|
||||
"uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
|
||||
"\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
|
||||
// opening quote
|
||||
do_str1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('\x22'); // '"'
|
||||
else
|
||||
return suspend(state::str1);
|
||||
|
||||
// fast loop,
|
||||
// copy unescaped
|
||||
do_str2:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
{
|
||||
std::size_t n = cs.remain();
|
||||
if(BOOST_JSON_LIKELY(n > 0))
|
||||
{
|
||||
if(ss.remain() > n)
|
||||
n = detail::count_unescaped(
|
||||
cs.data(), n);
|
||||
else
|
||||
n = detail::count_unescaped(
|
||||
cs.data(), ss.remain());
|
||||
if(n > 0)
|
||||
{
|
||||
ss.append(cs.data(), n);
|
||||
cs.skip(n);
|
||||
if(! ss)
|
||||
return suspend(state::str2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ss.append('\x22'); // '"'
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return suspend(state::str2);
|
||||
}
|
||||
|
||||
// slow loop,
|
||||
// handle escapes
|
||||
do_str3:
|
||||
while(BOOST_JSON_LIKELY(ss))
|
||||
{
|
||||
if(BOOST_JSON_LIKELY(cs))
|
||||
{
|
||||
auto const ch = *cs;
|
||||
auto const c = esc[static_cast<
|
||||
unsigned char>(ch)];
|
||||
++cs;
|
||||
if(! c)
|
||||
{
|
||||
ss.append(ch);
|
||||
}
|
||||
else if(c != 'u')
|
||||
{
|
||||
ss.append('\\');
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
{
|
||||
ss.append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf_[0] = c;
|
||||
return suspend(
|
||||
state::esc1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(BOOST_JSON_LIKELY(
|
||||
ss.remain() >= 6))
|
||||
{
|
||||
ss.append("\\u00", 4);
|
||||
ss.append(hex[static_cast<
|
||||
unsigned char>(ch) >> 4]);
|
||||
ss.append(hex[static_cast<
|
||||
unsigned char>(ch) & 15]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ss.append('\\');
|
||||
buf_[0] = hex[static_cast<
|
||||
unsigned char>(ch) >> 4];
|
||||
buf_[1] = hex[static_cast<
|
||||
unsigned char>(ch) & 15];
|
||||
goto do_utf1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ss.append('\x22'); // '"'
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return suspend(state::str3);
|
||||
|
||||
do_str4:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('\x22'); // '"'
|
||||
else
|
||||
return suspend(state::str4);
|
||||
|
||||
do_esc1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append(buf_[0]);
|
||||
else
|
||||
return suspend(state::esc1);
|
||||
goto do_str3;
|
||||
|
||||
do_utf1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('u');
|
||||
else
|
||||
return suspend(state::utf1);
|
||||
do_utf2:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('0');
|
||||
else
|
||||
return suspend(state::utf2);
|
||||
do_utf3:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('0');
|
||||
else
|
||||
return suspend(state::utf3);
|
||||
do_utf4:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append(buf_[0]);
|
||||
else
|
||||
return suspend(state::utf4);
|
||||
do_utf5:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append(buf_[1]);
|
||||
else
|
||||
return suspend(state::utf5);
|
||||
goto do_str3;
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_number(stream& ss0)
|
||||
{
|
||||
local_stream ss(ss0);
|
||||
if(StackEmpty || st_.empty())
|
||||
{
|
||||
switch(jv_->kind())
|
||||
{
|
||||
default:
|
||||
case kind::int64:
|
||||
if(BOOST_JSON_LIKELY(
|
||||
ss.remain() >=
|
||||
detail::max_number_chars))
|
||||
{
|
||||
ss.advance(detail::format_int64(
|
||||
ss.data(), jv_->get_int64()));
|
||||
return true;
|
||||
}
|
||||
cs0_ = { buf_, detail::format_int64(
|
||||
buf_, jv_->get_int64()) };
|
||||
break;
|
||||
|
||||
case kind::uint64:
|
||||
if(BOOST_JSON_LIKELY(
|
||||
ss.remain() >=
|
||||
detail::max_number_chars))
|
||||
{
|
||||
ss.advance(detail::format_uint64(
|
||||
ss.data(), jv_->get_uint64()));
|
||||
return true;
|
||||
}
|
||||
cs0_ = { buf_, detail::format_uint64(
|
||||
buf_, jv_->get_uint64()) };
|
||||
break;
|
||||
|
||||
case kind::double_:
|
||||
if(BOOST_JSON_LIKELY(
|
||||
ss.remain() >=
|
||||
detail::max_number_chars))
|
||||
{
|
||||
ss.advance(
|
||||
detail::format_double(
|
||||
ss.data(),
|
||||
jv_->get_double(),
|
||||
opts_.allow_infinity_and_nan));
|
||||
return true;
|
||||
}
|
||||
cs0_ = { buf_, detail::format_double(
|
||||
buf_, jv_->get_double(), opts_.allow_infinity_and_nan) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state st;
|
||||
st_.pop(st);
|
||||
BOOST_ASSERT(
|
||||
st == state::num);
|
||||
}
|
||||
auto const n = ss.remain();
|
||||
if(n < cs0_.remain())
|
||||
{
|
||||
ss.append(cs0_.data(), n);
|
||||
cs0_.skip(n);
|
||||
return suspend(state::num);
|
||||
}
|
||||
ss.append(
|
||||
cs0_.data(), cs0_.remain());
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_array(stream& ss0)
|
||||
{
|
||||
array const* pa;
|
||||
local_stream ss(ss0);
|
||||
array::const_iterator it;
|
||||
array::const_iterator end;
|
||||
if(StackEmpty || st_.empty())
|
||||
{
|
||||
pa = pa_;
|
||||
it = pa->begin();
|
||||
end = pa->end();
|
||||
}
|
||||
else
|
||||
{
|
||||
state st;
|
||||
st_.pop(st);
|
||||
st_.pop(it);
|
||||
st_.pop(pa);
|
||||
end = pa->end();
|
||||
switch(st)
|
||||
{
|
||||
default:
|
||||
case state::arr1: goto do_arr1;
|
||||
case state::arr2: goto do_arr2;
|
||||
case state::arr3: goto do_arr3;
|
||||
case state::arr4: goto do_arr4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
do_arr1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('[');
|
||||
else
|
||||
return suspend(
|
||||
state::arr1, it, pa);
|
||||
if(it == end)
|
||||
goto do_arr4;
|
||||
for(;;)
|
||||
{
|
||||
do_arr2:
|
||||
jv_ = &*it;
|
||||
if(! write_value<StackEmpty>(ss))
|
||||
return suspend(
|
||||
state::arr2, it, pa);
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
++it == end))
|
||||
break;
|
||||
do_arr3:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append(',');
|
||||
else
|
||||
return suspend(
|
||||
state::arr3, it, pa);
|
||||
}
|
||||
do_arr4:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append(']');
|
||||
else
|
||||
return suspend(
|
||||
state::arr4, it, pa);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_object(stream& ss0)
|
||||
{
|
||||
object const* po;
|
||||
local_stream ss(ss0);
|
||||
object::const_iterator it;
|
||||
object::const_iterator end;
|
||||
if(StackEmpty || st_.empty())
|
||||
{
|
||||
po = po_;
|
||||
it = po->begin();
|
||||
end = po->end();
|
||||
}
|
||||
else
|
||||
{
|
||||
state st;
|
||||
st_.pop(st);
|
||||
st_.pop(it);
|
||||
st_.pop(po);
|
||||
end = po->end();
|
||||
switch(st)
|
||||
{
|
||||
default:
|
||||
case state::obj1: goto do_obj1;
|
||||
case state::obj2: goto do_obj2;
|
||||
case state::obj3: goto do_obj3;
|
||||
case state::obj4: goto do_obj4;
|
||||
case state::obj5: goto do_obj5;
|
||||
case state::obj6: goto do_obj6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
do_obj1:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append('{');
|
||||
else
|
||||
return suspend(
|
||||
state::obj1, it, po);
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
it == end))
|
||||
goto do_obj6;
|
||||
for(;;)
|
||||
{
|
||||
cs0_ = {
|
||||
it->key().data(),
|
||||
it->key().size() };
|
||||
do_obj2:
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
! write_string<StackEmpty>(ss)))
|
||||
return suspend(
|
||||
state::obj2, it, po);
|
||||
do_obj3:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append(':');
|
||||
else
|
||||
return suspend(
|
||||
state::obj3, it, po);
|
||||
do_obj4:
|
||||
jv_ = &it->value();
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
! write_value<StackEmpty>(ss)))
|
||||
return suspend(
|
||||
state::obj4, it, po);
|
||||
++it;
|
||||
if(BOOST_JSON_UNLIKELY(it == end))
|
||||
break;
|
||||
do_obj5:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
ss.append(',');
|
||||
else
|
||||
return suspend(
|
||||
state::obj5, it, po);
|
||||
}
|
||||
do_obj6:
|
||||
if(BOOST_JSON_LIKELY(ss))
|
||||
{
|
||||
ss.append('}');
|
||||
return true;
|
||||
}
|
||||
return suspend(
|
||||
state::obj6, it, po);
|
||||
}
|
||||
|
||||
template<bool StackEmpty>
|
||||
bool
|
||||
serializer::
|
||||
write_value(stream& ss)
|
||||
{
|
||||
if(StackEmpty || st_.empty())
|
||||
{
|
||||
auto const& jv(*jv_);
|
||||
switch(jv.kind())
|
||||
{
|
||||
default:
|
||||
case kind::object:
|
||||
po_ = &jv.get_object();
|
||||
return write_object<true>(ss);
|
||||
|
||||
case kind::array:
|
||||
pa_ = &jv.get_array();
|
||||
return write_array<true>(ss);
|
||||
|
||||
case kind::string:
|
||||
{
|
||||
auto const& js = jv.get_string();
|
||||
cs0_ = { js.data(), js.size() };
|
||||
return write_string<true>(ss);
|
||||
}
|
||||
|
||||
case kind::int64:
|
||||
case kind::uint64:
|
||||
case kind::double_:
|
||||
return write_number<true>(ss);
|
||||
|
||||
case kind::bool_:
|
||||
if(jv.get_bool())
|
||||
{
|
||||
if(BOOST_JSON_LIKELY(
|
||||
ss.remain() >= 4))
|
||||
{
|
||||
ss.append("true", 4);
|
||||
return true;
|
||||
}
|
||||
return write_true<true>(ss);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(BOOST_JSON_LIKELY(
|
||||
ss.remain() >= 5))
|
||||
{
|
||||
ss.append("false", 5);
|
||||
return true;
|
||||
}
|
||||
return write_false<true>(ss);
|
||||
}
|
||||
|
||||
case kind::null:
|
||||
if(BOOST_JSON_LIKELY(
|
||||
ss.remain() >= 4))
|
||||
{
|
||||
ss.append("null", 4);
|
||||
return true;
|
||||
}
|
||||
return write_null<true>(ss);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state st;
|
||||
st_.peek(st);
|
||||
switch(st)
|
||||
{
|
||||
default:
|
||||
case state::nul1: case state::nul2:
|
||||
case state::nul3: case state::nul4:
|
||||
return write_null<StackEmpty>(ss);
|
||||
|
||||
case state::tru1: case state::tru2:
|
||||
case state::tru3: case state::tru4:
|
||||
return write_true<StackEmpty>(ss);
|
||||
|
||||
case state::fal1: case state::fal2:
|
||||
case state::fal3: case state::fal4:
|
||||
case state::fal5:
|
||||
return write_false<StackEmpty>(ss);
|
||||
|
||||
case state::str1: case state::str2:
|
||||
case state::str3: case state::str4:
|
||||
case state::esc1:
|
||||
case state::utf1: case state::utf2:
|
||||
case state::utf3: case state::utf4:
|
||||
case state::utf5:
|
||||
return write_string<StackEmpty>(ss);
|
||||
|
||||
case state::num:
|
||||
return write_number<StackEmpty>(ss);
|
||||
|
||||
case state::arr1: case state::arr2:
|
||||
case state::arr3: case state::arr4:
|
||||
return write_array<StackEmpty>(ss);
|
||||
|
||||
case state::obj1: case state::obj2:
|
||||
case state::obj3: case state::obj4:
|
||||
case state::obj5: case state::obj6:
|
||||
return write_object<StackEmpty>(ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_view
|
||||
serializer::
|
||||
read_some(
|
||||
char* dest, std::size_t size)
|
||||
{
|
||||
// If this goes off it means you forgot
|
||||
// to call reset() before seriailzing a
|
||||
// new value, or you never checked done()
|
||||
// to see if you should stop.
|
||||
BOOST_ASSERT(! done_);
|
||||
|
||||
stream ss(dest, size);
|
||||
if(st_.empty())
|
||||
(this->*fn0_)(ss);
|
||||
else
|
||||
(this->*fn1_)(ss);
|
||||
if(st_.empty())
|
||||
{
|
||||
done_ = true;
|
||||
jv_ = nullptr;
|
||||
}
|
||||
return string_view(
|
||||
dest, ss.used(dest));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
serializer::
|
||||
serializer( serialize_options const& opts ) noexcept
|
||||
: opts_(opts)
|
||||
{
|
||||
// ensure room for \uXXXX escape plus one
|
||||
BOOST_STATIC_ASSERT(
|
||||
sizeof(serializer::buf_) >= 7);
|
||||
}
|
||||
|
||||
void
|
||||
serializer::
|
||||
reset(value const* p) noexcept
|
||||
{
|
||||
pv_ = p;
|
||||
fn0_ = &serializer::write_value<true>;
|
||||
fn1_ = &serializer::write_value<false>;
|
||||
|
||||
jv_ = p;
|
||||
st_.clear();
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
serializer::
|
||||
reset(array const* p) noexcept
|
||||
{
|
||||
pa_ = p;
|
||||
fn0_ = &serializer::write_array<true>;
|
||||
fn1_ = &serializer::write_array<false>;
|
||||
st_.clear();
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
serializer::
|
||||
reset(object const* p) noexcept
|
||||
{
|
||||
po_ = p;
|
||||
fn0_ = &serializer::write_object<true>;
|
||||
fn1_ = &serializer::write_object<false>;
|
||||
st_.clear();
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
serializer::
|
||||
reset(string const* p) noexcept
|
||||
{
|
||||
cs0_ = { p->data(), p->size() };
|
||||
fn0_ = &serializer::write_string<true>;
|
||||
fn1_ = &serializer::write_string<false>;
|
||||
st_.clear();
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
serializer::
|
||||
reset(string_view sv) noexcept
|
||||
{
|
||||
cs0_ = { sv.data(), sv.size() };
|
||||
fn0_ = &serializer::write_string<true>;
|
||||
fn1_ = &serializer::write_string<false>;
|
||||
st_.clear();
|
||||
done_ = false;
|
||||
}
|
||||
|
||||
string_view
|
||||
serializer::
|
||||
read(char* dest, std::size_t size)
|
||||
{
|
||||
if(! jv_)
|
||||
{
|
||||
static value const null;
|
||||
jv_ = &null;
|
||||
}
|
||||
return read_some(dest, size);
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_STATIC_RESOURCE_IPP
|
||||
#define BOOST_JSON_IMPL_STATIC_RESOURCE_IPP
|
||||
|
||||
#include <boost/json/static_resource.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/align/align.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
static_resource::
|
||||
static_resource(
|
||||
unsigned char* buffer,
|
||||
std::size_t size) noexcept
|
||||
: p_(buffer)
|
||||
, n_(size)
|
||||
, size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
static_resource::
|
||||
release() noexcept
|
||||
{
|
||||
p_ = reinterpret_cast<
|
||||
char*>(p_) - (size_ - n_);
|
||||
n_ = size_;
|
||||
}
|
||||
|
||||
void*
|
||||
static_resource::
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align)
|
||||
{
|
||||
auto p = alignment::align(
|
||||
align, n, p_, n_);
|
||||
if(! p)
|
||||
throw_exception( std::bad_alloc(), BOOST_CURRENT_LOCATION );
|
||||
p_ = reinterpret_cast<char*>(p) + n;
|
||||
n_ -= n;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
static_resource::
|
||||
do_deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
bool
|
||||
static_resource::
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept
|
||||
{
|
||||
return this == &mr;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_STREAM_PARSER_IPP
|
||||
#define BOOST_JSON_IMPL_STREAM_PARSER_IPP
|
||||
|
||||
#include <boost/json/stream_parser.hpp>
|
||||
#include <boost/json/basic_parser_impl.hpp>
|
||||
#include <boost/json/error.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
stream_parser::
|
||||
stream_parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
unsigned char* buffer,
|
||||
std::size_t size) noexcept
|
||||
: p_(
|
||||
opt,
|
||||
std::move(sp),
|
||||
buffer,
|
||||
size)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
stream_parser::
|
||||
stream_parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt) noexcept
|
||||
: p_(
|
||||
opt,
|
||||
std::move(sp),
|
||||
nullptr,
|
||||
0)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void
|
||||
stream_parser::
|
||||
reset(storage_ptr sp) noexcept
|
||||
{
|
||||
p_.reset();
|
||||
p_.handler().st.reset(sp);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
stream_parser::
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
return p_.write_some(
|
||||
true, data, size, ec);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
stream_parser::
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
std::error_code& ec)
|
||||
{
|
||||
error_code jec;
|
||||
std::size_t const result = write_some(data, size, jec);
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
stream_parser::
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size)
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = write_some(
|
||||
data, size, ec);
|
||||
if(ec)
|
||||
detail::throw_system_error( ec );
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
stream_parser::
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = write_some(
|
||||
data, size, ec);
|
||||
if(! ec && n < size)
|
||||
{
|
||||
BOOST_JSON_FAIL(ec, error::extra_data);
|
||||
p_.fail(ec);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
stream_parser::
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
std::error_code& ec)
|
||||
{
|
||||
error_code jec;
|
||||
std::size_t const result = write(data, size, jec);
|
||||
ec = jec;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
stream_parser::
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size)
|
||||
{
|
||||
error_code ec;
|
||||
auto const n = write(
|
||||
data, size, ec);
|
||||
if(ec)
|
||||
detail::throw_system_error( ec );
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
stream_parser::
|
||||
finish(error_code& ec)
|
||||
{
|
||||
p_.write_some(false, nullptr, 0, ec);
|
||||
}
|
||||
|
||||
void
|
||||
stream_parser::
|
||||
finish()
|
||||
{
|
||||
error_code ec;
|
||||
finish(ec);
|
||||
if(ec)
|
||||
detail::throw_system_error( ec );
|
||||
}
|
||||
|
||||
void
|
||||
stream_parser::
|
||||
finish(std::error_code& ec)
|
||||
{
|
||||
error_code jec;
|
||||
finish(jec);
|
||||
ec = jec;
|
||||
}
|
||||
|
||||
value
|
||||
stream_parser::
|
||||
release()
|
||||
{
|
||||
if(! p_.done())
|
||||
{
|
||||
// prevent undefined behavior
|
||||
finish();
|
||||
}
|
||||
return p_.handler().st.release();
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_STRING_HPP
|
||||
#define BOOST_JSON_IMPL_STRING_HPP
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
string::
|
||||
string(
|
||||
detail::key_t const&,
|
||||
string_view s,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, impl_(detail::key_t{},
|
||||
s, sp_)
|
||||
{
|
||||
}
|
||||
|
||||
string::
|
||||
string(
|
||||
detail::key_t const&,
|
||||
string_view s1,
|
||||
string_view s2,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, impl_(detail::key_t{},
|
||||
s1, s2, sp_)
|
||||
{
|
||||
}
|
||||
|
||||
template<class InputIt, class>
|
||||
string::
|
||||
string(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
, impl_(first, last, sp_,
|
||||
iter_cat<InputIt>{})
|
||||
{
|
||||
}
|
||||
|
||||
template<class InputIt, class>
|
||||
string&
|
||||
string::
|
||||
assign(
|
||||
InputIt first,
|
||||
InputIt last)
|
||||
{
|
||||
assign(first, last,
|
||||
iter_cat<InputIt>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class InputIt, class>
|
||||
string&
|
||||
string::
|
||||
append(InputIt first, InputIt last)
|
||||
{
|
||||
append(first, last,
|
||||
iter_cat<InputIt>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
// KRYSTIAN TODO: this can be done without copies when
|
||||
// reallocation is not needed, when the iterator is a
|
||||
// FowardIterator or better, as we can use std::distance
|
||||
template<class InputIt, class>
|
||||
auto
|
||||
string::
|
||||
insert(
|
||||
size_type pos,
|
||||
InputIt first,
|
||||
InputIt last) ->
|
||||
string&
|
||||
{
|
||||
struct cleanup
|
||||
{
|
||||
detail::string_impl& s;
|
||||
storage_ptr const& sp;
|
||||
|
||||
~cleanup()
|
||||
{
|
||||
s.destroy(sp);
|
||||
}
|
||||
};
|
||||
|
||||
// We use the default storage because
|
||||
// the allocation is immediately freed.
|
||||
storage_ptr dsp;
|
||||
detail::string_impl tmp(
|
||||
first, last, dsp,
|
||||
iter_cat<InputIt>{});
|
||||
cleanup c{tmp, dsp};
|
||||
std::memcpy(
|
||||
impl_.insert_unchecked(pos, tmp.size(), sp_),
|
||||
tmp.data(),
|
||||
tmp.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// KRYSTIAN TODO: this can be done without copies when
|
||||
// reallocation is not needed, when the iterator is a
|
||||
// FowardIterator or better, as we can use std::distance
|
||||
template<class InputIt, class>
|
||||
auto
|
||||
string::
|
||||
replace(
|
||||
const_iterator first,
|
||||
const_iterator last,
|
||||
InputIt first2,
|
||||
InputIt last2) ->
|
||||
string&
|
||||
{
|
||||
struct cleanup
|
||||
{
|
||||
detail::string_impl& s;
|
||||
storage_ptr const& sp;
|
||||
|
||||
~cleanup()
|
||||
{
|
||||
s.destroy(sp);
|
||||
}
|
||||
};
|
||||
|
||||
// We use the default storage because
|
||||
// the allocation is immediately freed.
|
||||
storage_ptr dsp;
|
||||
detail::string_impl tmp(
|
||||
first2, last2, dsp,
|
||||
iter_cat<InputIt>{});
|
||||
cleanup c{tmp, dsp};
|
||||
std::memcpy(
|
||||
impl_.replace_unchecked(
|
||||
first - begin(),
|
||||
last - first,
|
||||
tmp.size(),
|
||||
sp_),
|
||||
tmp.data(),
|
||||
tmp.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
string::
|
||||
assign(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::random_access_iterator_tag)
|
||||
{
|
||||
auto dest = impl_.assign(static_cast<
|
||||
size_type>(last - first), sp_);
|
||||
while(first != last)
|
||||
*dest++ = *first++;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
string::
|
||||
assign(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::input_iterator_tag)
|
||||
{
|
||||
if(first == last)
|
||||
{
|
||||
impl_.term(0);
|
||||
return;
|
||||
}
|
||||
detail::string_impl tmp(
|
||||
first, last, sp_,
|
||||
std::input_iterator_tag{});
|
||||
impl_.destroy(sp_);
|
||||
impl_ = tmp;
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
string::
|
||||
append(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::random_access_iterator_tag)
|
||||
{
|
||||
|
||||
auto const n = static_cast<
|
||||
size_type>(last - first);
|
||||
char* out = impl_.append(n, sp_);
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1900
|
||||
while( first != last )
|
||||
*out++ = *first++;
|
||||
#else
|
||||
std::copy(first, last, out);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class InputIt>
|
||||
void
|
||||
string::
|
||||
append(
|
||||
InputIt first,
|
||||
InputIt last,
|
||||
std::input_iterator_tag)
|
||||
{
|
||||
struct cleanup
|
||||
{
|
||||
detail::string_impl& s;
|
||||
storage_ptr const& sp;
|
||||
|
||||
~cleanup()
|
||||
{
|
||||
s.destroy(sp);
|
||||
}
|
||||
};
|
||||
|
||||
// We use the default storage because
|
||||
// the allocation is immediately freed.
|
||||
storage_ptr dsp;
|
||||
detail::string_impl tmp(
|
||||
first, last, dsp,
|
||||
std::input_iterator_tag{});
|
||||
cleanup c{tmp, dsp};
|
||||
std::memcpy(
|
||||
impl_.append(tmp.size(), sp_),
|
||||
tmp.data(), tmp.size());
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+431
@@ -0,0 +1,431 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_STRING_IPP
|
||||
#define BOOST_JSON_IMPL_STRING_IPP
|
||||
|
||||
#include <boost/json/detail/except.hpp>
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Construction
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
string::
|
||||
string(
|
||||
std::size_t count,
|
||||
char ch,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
assign(count, ch);
|
||||
}
|
||||
|
||||
string::
|
||||
string(
|
||||
char const* s,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
assign(s);
|
||||
}
|
||||
|
||||
string::
|
||||
string(
|
||||
char const* s,
|
||||
std::size_t count,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
assign(s, count);
|
||||
}
|
||||
|
||||
string::
|
||||
string(string const& other)
|
||||
: sp_(other.sp_)
|
||||
{
|
||||
assign(other);
|
||||
}
|
||||
|
||||
string::
|
||||
string(
|
||||
string const& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
assign(other);
|
||||
}
|
||||
|
||||
string::
|
||||
string(
|
||||
string&& other,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
assign(std::move(other));
|
||||
}
|
||||
|
||||
string::
|
||||
string(
|
||||
string_view s,
|
||||
storage_ptr sp)
|
||||
: sp_(std::move(sp))
|
||||
{
|
||||
assign(s);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Assignment
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
string&
|
||||
string::
|
||||
operator=(string const& other)
|
||||
{
|
||||
return assign(other);
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
operator=(string&& other)
|
||||
{
|
||||
return assign(std::move(other));
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
operator=(char const* s)
|
||||
{
|
||||
return assign(s);
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
operator=(string_view s)
|
||||
{
|
||||
return assign(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
string&
|
||||
string::
|
||||
assign(
|
||||
size_type count,
|
||||
char ch)
|
||||
{
|
||||
std::char_traits<char>::assign(
|
||||
impl_.assign(count, sp_),
|
||||
count,
|
||||
ch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
assign(
|
||||
string const& other)
|
||||
{
|
||||
if(this == &other)
|
||||
return *this;
|
||||
return assign(
|
||||
other.data(),
|
||||
other.size());
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
assign(string&& other)
|
||||
{
|
||||
if( &other == this )
|
||||
return *this;
|
||||
|
||||
if(*sp_ == *other.sp_)
|
||||
{
|
||||
impl_.destroy(sp_);
|
||||
impl_ = other.impl_;
|
||||
::new(&other.impl_) detail::string_impl();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// copy
|
||||
return assign(other);
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
assign(
|
||||
char const* s,
|
||||
size_type count)
|
||||
{
|
||||
std::char_traits<char>::copy(
|
||||
impl_.assign(count, sp_),
|
||||
s, count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
assign(
|
||||
char const* s)
|
||||
{
|
||||
return assign(s, std::char_traits<
|
||||
char>::length(s));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Capacity
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
string::
|
||||
shrink_to_fit()
|
||||
{
|
||||
impl_.shrink_to_fit(sp_);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Operations
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
string::
|
||||
clear() noexcept
|
||||
{
|
||||
impl_.term(0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
string::
|
||||
push_back(char ch)
|
||||
{
|
||||
*impl_.append(1, sp_) = ch;
|
||||
}
|
||||
|
||||
void
|
||||
string::
|
||||
pop_back()
|
||||
{
|
||||
back() = 0;
|
||||
impl_.size(impl_.size() - 1);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
string&
|
||||
string::
|
||||
append(size_type count, char ch)
|
||||
{
|
||||
std::char_traits<char>::assign(
|
||||
impl_.append(count, sp_),
|
||||
count, ch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
append(string_view sv)
|
||||
{
|
||||
std::char_traits<char>::copy(
|
||||
impl_.append(sv.size(), sp_),
|
||||
sv.data(), sv.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
string&
|
||||
string::
|
||||
insert(
|
||||
size_type pos,
|
||||
string_view sv)
|
||||
{
|
||||
impl_.insert(pos, sv.data(), sv.size(), sp_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
insert(
|
||||
std::size_t pos,
|
||||
std::size_t count,
|
||||
char ch)
|
||||
{
|
||||
std::char_traits<char>::assign(
|
||||
impl_.insert_unchecked(pos, count, sp_),
|
||||
count, ch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
string&
|
||||
string::
|
||||
replace(
|
||||
std::size_t pos,
|
||||
std::size_t count,
|
||||
string_view sv)
|
||||
{
|
||||
impl_.replace(pos, count, sv.data(), sv.size(), sp_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string&
|
||||
string::
|
||||
replace(
|
||||
std::size_t pos,
|
||||
std::size_t count,
|
||||
std::size_t count2,
|
||||
char ch)
|
||||
{
|
||||
std::char_traits<char>::assign(
|
||||
impl_.replace_unchecked(pos, count, count2, sp_),
|
||||
count2, ch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
string&
|
||||
string::
|
||||
erase(
|
||||
size_type pos,
|
||||
size_type count)
|
||||
{
|
||||
if(pos > impl_.size())
|
||||
{
|
||||
BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
|
||||
detail::throw_system_error( error::out_of_range, &loc );
|
||||
}
|
||||
if( count > impl_.size() - pos)
|
||||
count = impl_.size() - pos;
|
||||
std::char_traits<char>::move(
|
||||
impl_.data() + pos,
|
||||
impl_.data() + pos + count,
|
||||
impl_.size() - pos - count + 1);
|
||||
impl_.term(impl_.size() - count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto
|
||||
string::
|
||||
erase(const_iterator pos) ->
|
||||
iterator
|
||||
{
|
||||
return erase(pos, pos+1);
|
||||
}
|
||||
|
||||
auto
|
||||
string::
|
||||
erase(
|
||||
const_iterator first,
|
||||
const_iterator last) ->
|
||||
iterator
|
||||
{
|
||||
auto const pos = first - begin();
|
||||
auto const count = last - first;
|
||||
erase(pos, count);
|
||||
return data() + pos;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
string::
|
||||
resize(size_type count, char ch)
|
||||
{
|
||||
if(count <= impl_.size())
|
||||
{
|
||||
impl_.term(count);
|
||||
return;
|
||||
}
|
||||
|
||||
reserve(count);
|
||||
std::char_traits<char>::assign(
|
||||
impl_.end(),
|
||||
count - impl_.size(),
|
||||
ch);
|
||||
grow(count - size());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
string::
|
||||
swap(string& other)
|
||||
{
|
||||
if(*sp_ == *other.sp_)
|
||||
{
|
||||
std::swap(impl_, other.impl_);
|
||||
return;
|
||||
}
|
||||
string temp1(
|
||||
std::move(*this), other.sp_);
|
||||
string temp2(
|
||||
std::move(other), sp_);
|
||||
this->~string();
|
||||
::new(this) string(pilfer(temp2));
|
||||
other.~string();
|
||||
::new(&other) string(pilfer(temp1));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
string::
|
||||
reserve_impl(size_type new_cap)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
new_cap >= impl_.capacity());
|
||||
if(new_cap > impl_.capacity())
|
||||
{
|
||||
// grow
|
||||
new_cap = detail::string_impl::growth(
|
||||
new_cap, impl_.capacity());
|
||||
detail::string_impl tmp(new_cap, sp_);
|
||||
std::char_traits<char>::copy(tmp.data(),
|
||||
impl_.data(), impl_.size() + 1);
|
||||
tmp.size(impl_.size());
|
||||
impl_.destroy(sp_);
|
||||
impl_ = tmp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
std::size_t
|
||||
std::hash< ::boost::json::string >::operator()(
|
||||
::boost::json::string const& js ) const noexcept
|
||||
{
|
||||
return ::boost::hash< ::boost::json::string >()( js );
|
||||
}
|
||||
|
||||
#endif
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright (c) 2022 Dmitry Arkhipov (grisumbras@yandex.ru)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_VALUE_HPP
|
||||
#define BOOST_JSON_IMPL_VALUE_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
value&
|
||||
value::at_pointer(string_view ptr) &
|
||||
{
|
||||
auto const& self = *this;
|
||||
return const_cast<value&>( self.at_pointer(ptr) );
|
||||
}
|
||||
|
||||
value&&
|
||||
value::at_pointer(string_view ptr) &&
|
||||
{
|
||||
return std::move( this->at_pointer(ptr) );
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_JSON_IMPL_VALUE_HPP
|
||||
+714
@@ -0,0 +1,714 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_VALUE_IPP
|
||||
#define BOOST_JSON_IMPL_VALUE_IPP
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/parser.hpp>
|
||||
#include <cstring>
|
||||
#include <istream>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
int parse_depth_xalloc = std::ios::xalloc();
|
||||
int parse_flags_xalloc = std::ios::xalloc();
|
||||
|
||||
struct value_hasher
|
||||
{
|
||||
std::size_t& seed;
|
||||
|
||||
template< class T >
|
||||
void operator()( T&& t ) const noexcept
|
||||
{
|
||||
boost::hash_combine( seed, t );
|
||||
}
|
||||
};
|
||||
|
||||
enum class stream_parse_flags
|
||||
{
|
||||
allow_comments = 1 << 0,
|
||||
allow_trailing_commas = 1 << 1,
|
||||
allow_invalid_utf8 = 1 << 2,
|
||||
};
|
||||
|
||||
long
|
||||
to_bitmask( parse_options const& opts )
|
||||
{
|
||||
using E = stream_parse_flags;
|
||||
return
|
||||
(opts.allow_comments ?
|
||||
static_cast<long>(E::allow_comments) : 0) |
|
||||
(opts.allow_trailing_commas ?
|
||||
static_cast<long>(E::allow_trailing_commas) : 0) |
|
||||
(opts.allow_invalid_utf8 ?
|
||||
static_cast<long>(E::allow_invalid_utf8) : 0);
|
||||
}
|
||||
|
||||
parse_options
|
||||
get_parse_options( std::istream& is )
|
||||
{
|
||||
long const flags = is.iword(parse_flags_xalloc);
|
||||
|
||||
using E = stream_parse_flags;
|
||||
parse_options opts;
|
||||
opts.allow_comments =
|
||||
flags & static_cast<long>(E::allow_comments) ? true : false;
|
||||
opts.allow_trailing_commas =
|
||||
flags & static_cast<long>(E::allow_trailing_commas) ? true : false;
|
||||
opts.allow_invalid_utf8 =
|
||||
flags & static_cast<long>(E::allow_invalid_utf8) ? true : false;
|
||||
return opts;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
value::
|
||||
~value() noexcept
|
||||
{
|
||||
switch(kind())
|
||||
{
|
||||
case json::kind::null:
|
||||
case json::kind::bool_:
|
||||
case json::kind::int64:
|
||||
case json::kind::uint64:
|
||||
case json::kind::double_:
|
||||
sca_.~scalar();
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
str_.~string();
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
arr_.~array();
|
||||
break;
|
||||
|
||||
case json::kind::object:
|
||||
obj_.~object();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value::
|
||||
value(
|
||||
value const& other,
|
||||
storage_ptr sp)
|
||||
{
|
||||
switch(other.kind())
|
||||
{
|
||||
case json::kind::null:
|
||||
::new(&sca_) scalar(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::bool_:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.b,
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::int64:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.i,
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::uint64:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.u,
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::double_:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.d,
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
::new(&str_) string(
|
||||
other.str_,
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
::new(&arr_) array(
|
||||
other.arr_,
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::object:
|
||||
::new(&obj_) object(
|
||||
other.obj_,
|
||||
std::move(sp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value::
|
||||
value(value&& other) noexcept
|
||||
{
|
||||
relocate(this, other);
|
||||
::new(&other.sca_) scalar(sp_);
|
||||
}
|
||||
|
||||
value::
|
||||
value(
|
||||
value&& other,
|
||||
storage_ptr sp)
|
||||
{
|
||||
switch(other.kind())
|
||||
{
|
||||
case json::kind::null:
|
||||
::new(&sca_) scalar(
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::bool_:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.b, std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::int64:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.i, std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::uint64:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.u, std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::double_:
|
||||
::new(&sca_) scalar(
|
||||
other.sca_.d, std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
::new(&str_) string(
|
||||
std::move(other.str_),
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::array:
|
||||
::new(&arr_) array(
|
||||
std::move(other.arr_),
|
||||
std::move(sp));
|
||||
break;
|
||||
|
||||
case json::kind::object:
|
||||
::new(&obj_) object(
|
||||
std::move(other.obj_),
|
||||
std::move(sp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Conversion
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
value::
|
||||
value(
|
||||
std::initializer_list<value_ref> init,
|
||||
storage_ptr sp)
|
||||
{
|
||||
if(value_ref::maybe_object(init))
|
||||
{
|
||||
::new(&obj_) object(
|
||||
value_ref::make_object(
|
||||
init, std::move(sp)));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef BOOST_JSON_LEGACY_INIT_LIST_BEHAVIOR
|
||||
if( init.size() == 1 )
|
||||
{
|
||||
::new(&sca_) scalar();
|
||||
value temp = init.begin()->make_value( std::move(sp) );
|
||||
swap(temp);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
::new(&arr_) array(
|
||||
value_ref::make_array(
|
||||
init, std::move(sp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Assignment
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(value const& other)
|
||||
{
|
||||
value(other,
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(value&& other)
|
||||
{
|
||||
value(std::move(other),
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(
|
||||
std::initializer_list<value_ref> init)
|
||||
{
|
||||
value(init,
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(string_view s)
|
||||
{
|
||||
value(s, storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(char const* s)
|
||||
{
|
||||
value(s, storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(string const& str)
|
||||
{
|
||||
value(str, storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(string&& str)
|
||||
{
|
||||
value(std::move(str),
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(array const& arr)
|
||||
{
|
||||
value(arr, storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(array&& arr)
|
||||
{
|
||||
value(std::move(arr),
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(object const& obj)
|
||||
{
|
||||
value(obj, storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
value&
|
||||
value::
|
||||
operator=(object&& obj)
|
||||
{
|
||||
value(std::move(obj),
|
||||
storage()).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Modifiers
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
string&
|
||||
value::
|
||||
emplace_string() noexcept
|
||||
{
|
||||
return *::new(&str_) string(destroy());
|
||||
}
|
||||
|
||||
array&
|
||||
value::
|
||||
emplace_array() noexcept
|
||||
{
|
||||
return *::new(&arr_) array(destroy());
|
||||
}
|
||||
|
||||
object&
|
||||
value::
|
||||
emplace_object() noexcept
|
||||
{
|
||||
return *::new(&obj_) object(destroy());
|
||||
}
|
||||
|
||||
void
|
||||
value::
|
||||
swap(value& other)
|
||||
{
|
||||
if(*storage() == *other.storage())
|
||||
{
|
||||
// fast path
|
||||
union U
|
||||
{
|
||||
value tmp;
|
||||
U(){}
|
||||
~U(){}
|
||||
};
|
||||
U u;
|
||||
relocate(&u.tmp, *this);
|
||||
relocate(this, other);
|
||||
relocate(&other, u.tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
// copy
|
||||
value temp1(
|
||||
std::move(*this),
|
||||
other.storage());
|
||||
value temp2(
|
||||
std::move(other),
|
||||
this->storage());
|
||||
other.~value();
|
||||
::new(&other) value(pilfer(temp1));
|
||||
this->~value();
|
||||
::new(this) value(pilfer(temp2));
|
||||
}
|
||||
|
||||
std::istream&
|
||||
operator>>(
|
||||
std::istream& is,
|
||||
value& jv)
|
||||
{
|
||||
using Traits = std::istream::traits_type;
|
||||
|
||||
// sentry prepares the stream for reading and finalizes it in destructor
|
||||
std::istream::sentry sentry(is);
|
||||
if( !sentry )
|
||||
return is;
|
||||
|
||||
parse_options opts = get_parse_options( is );
|
||||
if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
|
||||
opts.max_depth = depth;
|
||||
|
||||
unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
|
||||
stream_parser p( {}, opts, parser_buf );
|
||||
p.reset( jv.storage() );
|
||||
|
||||
char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
|
||||
std::streambuf& buf = *is.rdbuf();
|
||||
std::ios::iostate err = std::ios::goodbit;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
#endif
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
error_code ec;
|
||||
|
||||
// we peek the buffer; this either makes sure that there's no
|
||||
// more input, or makes sure there's something in the internal
|
||||
// buffer (so in_avail will return a positive number)
|
||||
std::istream::int_type c = is.rdbuf()->sgetc();
|
||||
// if we indeed reached EOF, we check if we parsed a full JSON
|
||||
// document; if not, we error out
|
||||
if( Traits::eq_int_type(c, Traits::eof()) )
|
||||
{
|
||||
err |= std::ios::eofbit;
|
||||
p.finish(ec);
|
||||
if( ec.failed() )
|
||||
break;
|
||||
}
|
||||
|
||||
// regardless of reaching EOF, we might have parsed a full JSON
|
||||
// document; if so, we successfully finish
|
||||
if( p.done() )
|
||||
{
|
||||
jv = p.release();
|
||||
return is;
|
||||
}
|
||||
|
||||
// at this point we definitely have more input, specifically in
|
||||
// buf's internal buffer; we also definitely haven't parsed a whole
|
||||
// document
|
||||
std::streamsize available = buf.in_avail();
|
||||
// if this assert fails, the streambuf is buggy
|
||||
BOOST_ASSERT( available > 0 );
|
||||
|
||||
available = ( std::min )(
|
||||
static_cast<std::size_t>(available), sizeof(read_buf) );
|
||||
// we read from the internal buffer of buf into our buffer
|
||||
available = buf.sgetn( read_buf, available );
|
||||
|
||||
std::size_t consumed = p.write_some(
|
||||
read_buf, static_cast<std::size_t>(available), ec );
|
||||
// if the parser hasn't consumed the entire input we've took from
|
||||
// buf, we put the remaining data back; this should succeed,
|
||||
// because we only read data from buf's internal buffer
|
||||
while( consumed++ < static_cast<std::size_t>(available) )
|
||||
{
|
||||
std::istream::int_type const status = buf.sungetc();
|
||||
BOOST_ASSERT( status != Traits::eof() );
|
||||
(void)status;
|
||||
}
|
||||
|
||||
if( ec.failed() )
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...)
|
||||
{
|
||||
try
|
||||
{
|
||||
is.setstate(std::ios::badbit);
|
||||
}
|
||||
// we ignore the exception, because we need to throw the original
|
||||
// exception instead
|
||||
catch( std::ios::failure const& ) { }
|
||||
|
||||
if( is.exceptions() & std::ios::badbit )
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
|
||||
is.setstate(err | std::ios::failbit);
|
||||
return is;
|
||||
}
|
||||
|
||||
std::istream&
|
||||
operator>>(
|
||||
std::istream& is,
|
||||
parse_options const& opts)
|
||||
{
|
||||
is.iword(parse_flags_xalloc) = to_bitmask(opts);
|
||||
is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
|
||||
return is;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// private
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
storage_ptr
|
||||
value::
|
||||
destroy() noexcept
|
||||
{
|
||||
switch(kind())
|
||||
{
|
||||
case json::kind::null:
|
||||
case json::kind::bool_:
|
||||
case json::kind::int64:
|
||||
case json::kind::uint64:
|
||||
case json::kind::double_:
|
||||
break;
|
||||
|
||||
case json::kind::string:
|
||||
{
|
||||
auto sp = str_.storage();
|
||||
str_.~string();
|
||||
return sp;
|
||||
}
|
||||
|
||||
case json::kind::array:
|
||||
{
|
||||
auto sp = arr_.storage();
|
||||
arr_.~array();
|
||||
return sp;
|
||||
}
|
||||
|
||||
case json::kind::object:
|
||||
{
|
||||
auto sp = obj_.storage();
|
||||
obj_.~object();
|
||||
return sp;
|
||||
}
|
||||
|
||||
}
|
||||
return std::move(sp_);
|
||||
}
|
||||
|
||||
bool
|
||||
value::
|
||||
equal(value const& other) const noexcept
|
||||
{
|
||||
switch(kind())
|
||||
{
|
||||
default: // unreachable()?
|
||||
case json::kind::null:
|
||||
return other.kind() == json::kind::null;
|
||||
|
||||
case json::kind::bool_:
|
||||
return
|
||||
other.kind() == json::kind::bool_ &&
|
||||
get_bool() == other.get_bool();
|
||||
|
||||
case json::kind::int64:
|
||||
switch(other.kind())
|
||||
{
|
||||
case json::kind::int64:
|
||||
return get_int64() == other.get_int64();
|
||||
case json::kind::uint64:
|
||||
if(get_int64() < 0)
|
||||
return false;
|
||||
return static_cast<std::uint64_t>(
|
||||
get_int64()) == other.get_uint64();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
case json::kind::uint64:
|
||||
switch(other.kind())
|
||||
{
|
||||
case json::kind::uint64:
|
||||
return get_uint64() == other.get_uint64();
|
||||
case json::kind::int64:
|
||||
if(other.get_int64() < 0)
|
||||
return false;
|
||||
return static_cast<std::uint64_t>(
|
||||
other.get_int64()) == get_uint64();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
case json::kind::double_:
|
||||
return
|
||||
other.kind() == json::kind::double_ &&
|
||||
get_double() == other.get_double();
|
||||
|
||||
case json::kind::string:
|
||||
return
|
||||
other.kind() == json::kind::string &&
|
||||
get_string() == other.get_string();
|
||||
|
||||
case json::kind::array:
|
||||
return
|
||||
other.kind() == json::kind::array &&
|
||||
get_array() == other.get_array();
|
||||
|
||||
case json::kind::object:
|
||||
return
|
||||
other.kind() == json::kind::object &&
|
||||
get_object() == other.get_object();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// key_value_pair
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
// empty keys point here
|
||||
BOOST_JSON_REQUIRE_CONST_INIT
|
||||
char const
|
||||
key_value_pair::empty_[1] = { 0 };
|
||||
|
||||
key_value_pair::
|
||||
key_value_pair(
|
||||
pilfered<json::value> key,
|
||||
pilfered<json::value> value) noexcept
|
||||
: value_(value)
|
||||
{
|
||||
std::size_t len;
|
||||
key_ = access::release_key(key.get(), len);
|
||||
len_ = static_cast<std::uint32_t>(len);
|
||||
}
|
||||
|
||||
key_value_pair::
|
||||
key_value_pair(
|
||||
key_value_pair const& other,
|
||||
storage_ptr sp)
|
||||
: value_(other.value_, std::move(sp))
|
||||
{
|
||||
auto p = reinterpret_cast<
|
||||
char*>(value_.storage()->
|
||||
allocate(other.len_ + 1,
|
||||
alignof(char)));
|
||||
std::memcpy(
|
||||
p, other.key_, other.len_);
|
||||
len_ = other.len_;
|
||||
p[len_] = 0;
|
||||
key_ = p;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
std::size_t
|
||||
hash_value_impl( value const& jv ) noexcept
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
kind const k = jv.kind();
|
||||
boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
|
||||
|
||||
visit( value_hasher{seed}, jv );
|
||||
return seed;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// std::hash specialization
|
||||
//
|
||||
//----------------------------------------------------------
|
||||
|
||||
std::size_t
|
||||
std::hash<::boost::json::value>::operator()(
|
||||
::boost::json::value const& jv) const noexcept
|
||||
{
|
||||
return ::boost::hash< ::boost::json::value >()( jv );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
#endif
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_VALUE_REF_HPP
|
||||
#define BOOST_JSON_IMPL_VALUE_REF_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template<class T>
|
||||
value
|
||||
value_ref::
|
||||
from_builtin(
|
||||
void const* p,
|
||||
storage_ptr sp) noexcept
|
||||
{
|
||||
return value(
|
||||
*reinterpret_cast<
|
||||
T const*>(p),
|
||||
std::move(sp));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
value
|
||||
value_ref::
|
||||
from_const(
|
||||
void const* p,
|
||||
storage_ptr sp)
|
||||
{
|
||||
return value(
|
||||
*reinterpret_cast<
|
||||
T const*>(p),
|
||||
std::move(sp));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
value
|
||||
value_ref::
|
||||
from_rvalue(
|
||||
void* p,
|
||||
storage_ptr sp)
|
||||
{
|
||||
return value(
|
||||
std::move(
|
||||
*reinterpret_cast<T*>(p)),
|
||||
std::move(sp));
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_VALUE_REF_IPP
|
||||
#define BOOST_JSON_IMPL_VALUE_REF_IPP
|
||||
|
||||
#include <boost/json/value_ref.hpp>
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
value_ref::
|
||||
operator
|
||||
value() const
|
||||
{
|
||||
return make_value({});
|
||||
}
|
||||
|
||||
value
|
||||
value_ref::
|
||||
from_init_list(
|
||||
void const* p,
|
||||
storage_ptr sp)
|
||||
{
|
||||
return make_value(
|
||||
*reinterpret_cast<
|
||||
init_list const*>(p),
|
||||
std::move(sp));
|
||||
}
|
||||
|
||||
bool
|
||||
value_ref::
|
||||
is_key_value_pair() const noexcept
|
||||
{
|
||||
if(what_ != what::ini)
|
||||
return false;
|
||||
if(arg_.init_list_.size() != 2)
|
||||
return false;
|
||||
auto const& e =
|
||||
*arg_.init_list_.begin();
|
||||
if( e.what_ != what::str &&
|
||||
e.what_ != what::strfunc)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
value_ref::
|
||||
maybe_object(
|
||||
std::initializer_list<
|
||||
value_ref> init) noexcept
|
||||
{
|
||||
for(auto const& e : init)
|
||||
if(! e.is_key_value_pair())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
string_view
|
||||
value_ref::
|
||||
get_string() const noexcept
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
what_ == what::str ||
|
||||
what_ == what::strfunc);
|
||||
if (what_ == what::strfunc)
|
||||
return *static_cast<const string*>(f_.p);
|
||||
return arg_.str_;
|
||||
}
|
||||
|
||||
value
|
||||
value_ref::
|
||||
make_value(
|
||||
storage_ptr sp) const
|
||||
{
|
||||
switch(what_)
|
||||
{
|
||||
default:
|
||||
case what::str:
|
||||
return string(
|
||||
arg_.str_,
|
||||
std::move(sp));
|
||||
|
||||
case what::ini:
|
||||
return make_value(
|
||||
arg_.init_list_,
|
||||
std::move(sp));
|
||||
|
||||
case what::func:
|
||||
return f_.f(f_.p,
|
||||
std::move(sp));
|
||||
|
||||
case what::strfunc:
|
||||
return f_.f(f_.p,
|
||||
std::move(sp));
|
||||
|
||||
case what::cfunc:
|
||||
return cf_.f(cf_.p,
|
||||
std::move(sp));
|
||||
}
|
||||
}
|
||||
|
||||
value
|
||||
value_ref::
|
||||
make_value(
|
||||
std::initializer_list<
|
||||
value_ref> init,
|
||||
storage_ptr sp)
|
||||
{
|
||||
if(maybe_object(init))
|
||||
return make_object(
|
||||
init, std::move(sp));
|
||||
return make_array(
|
||||
init, std::move(sp));
|
||||
}
|
||||
|
||||
object
|
||||
value_ref::
|
||||
make_object(
|
||||
std::initializer_list<value_ref> init,
|
||||
storage_ptr sp)
|
||||
{
|
||||
object obj(std::move(sp));
|
||||
obj.reserve(init.size());
|
||||
for(auto const& e : init)
|
||||
obj.emplace(
|
||||
e.arg_.init_list_.begin()[0].get_string(),
|
||||
e.arg_.init_list_.begin()[1].make_value(
|
||||
obj.storage()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
array
|
||||
value_ref::
|
||||
make_array(
|
||||
std::initializer_list<
|
||||
value_ref> init,
|
||||
storage_ptr sp)
|
||||
{
|
||||
array arr(std::move(sp));
|
||||
arr.reserve(init.size());
|
||||
for(auto const& e : init)
|
||||
arr.emplace_back(
|
||||
e.make_value(
|
||||
arr.storage()));
|
||||
return arr;
|
||||
}
|
||||
|
||||
void
|
||||
value_ref::
|
||||
write_array(
|
||||
value* dest,
|
||||
std::initializer_list<
|
||||
value_ref> init,
|
||||
storage_ptr const& sp)
|
||||
{
|
||||
struct undo
|
||||
{
|
||||
value* const base;
|
||||
value* pos;
|
||||
~undo()
|
||||
{
|
||||
if(pos)
|
||||
while(pos > base)
|
||||
(--pos)->~value();
|
||||
}
|
||||
};
|
||||
undo u{dest, dest};
|
||||
for(auto const& e : init)
|
||||
{
|
||||
::new(u.pos) value(
|
||||
e.make_value(sp));
|
||||
++u.pos;
|
||||
}
|
||||
u.pos = nullptr;
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+476
@@ -0,0 +1,476 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_VALUE_STACK_IPP
|
||||
#define BOOST_JSON_IMPL_VALUE_STACK_IPP
|
||||
|
||||
#include <boost/json/value_stack.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
value_stack::
|
||||
stack::
|
||||
~stack()
|
||||
{
|
||||
clear();
|
||||
if( begin_ != temp_ &&
|
||||
begin_ != nullptr)
|
||||
sp_->deallocate(
|
||||
begin_,
|
||||
(end_ - begin_) *
|
||||
sizeof(value));
|
||||
}
|
||||
|
||||
value_stack::
|
||||
stack::
|
||||
stack(
|
||||
storage_ptr sp,
|
||||
void* temp,
|
||||
std::size_t size) noexcept
|
||||
: sp_(std::move(sp))
|
||||
, temp_(temp)
|
||||
{
|
||||
if(size >= min_size_ *
|
||||
sizeof(value))
|
||||
{
|
||||
begin_ = reinterpret_cast<
|
||||
value*>(temp);
|
||||
top_ = begin_;
|
||||
end_ = begin_ +
|
||||
size / sizeof(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
begin_ = nullptr;
|
||||
top_ = nullptr;
|
||||
end_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
stack::
|
||||
run_dtors(bool b) noexcept
|
||||
{
|
||||
run_dtors_ = b;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
value_stack::
|
||||
stack::
|
||||
size() const noexcept
|
||||
{
|
||||
return top_ - begin_;
|
||||
}
|
||||
|
||||
bool
|
||||
value_stack::
|
||||
stack::
|
||||
has_chars()
|
||||
{
|
||||
return chars_ != 0;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
// destroy the values but
|
||||
// not the stack allocation.
|
||||
void
|
||||
value_stack::
|
||||
stack::
|
||||
clear() noexcept
|
||||
{
|
||||
if(top_ != begin_)
|
||||
{
|
||||
if(run_dtors_)
|
||||
for(auto it = top_;
|
||||
it-- != begin_;)
|
||||
it->~value();
|
||||
top_ = begin_;
|
||||
}
|
||||
chars_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
stack::
|
||||
maybe_grow()
|
||||
{
|
||||
if(top_ >= end_)
|
||||
grow_one();
|
||||
}
|
||||
|
||||
// make room for at least one more value
|
||||
void
|
||||
value_stack::
|
||||
stack::
|
||||
grow_one()
|
||||
{
|
||||
BOOST_ASSERT(chars_ == 0);
|
||||
std::size_t const capacity =
|
||||
end_ - begin_;
|
||||
std::size_t new_cap = min_size_;
|
||||
// VFALCO check overflow here
|
||||
while(new_cap < capacity + 1)
|
||||
new_cap <<= 1;
|
||||
auto const begin =
|
||||
reinterpret_cast<value*>(
|
||||
sp_->allocate(
|
||||
new_cap * sizeof(value)));
|
||||
std::size_t const cur_size = top_ - begin_;
|
||||
if(begin_)
|
||||
{
|
||||
std::memcpy(
|
||||
reinterpret_cast<char*>(begin),
|
||||
reinterpret_cast<char*>(begin_),
|
||||
size() * sizeof(value));
|
||||
if(begin_ != temp_)
|
||||
sp_->deallocate(begin_,
|
||||
capacity * sizeof(value));
|
||||
}
|
||||
// book-keeping
|
||||
top_ = begin + cur_size;
|
||||
end_ = begin + new_cap;
|
||||
begin_ = begin;
|
||||
}
|
||||
|
||||
// make room for nchars additional characters.
|
||||
void
|
||||
value_stack::
|
||||
stack::
|
||||
grow(std::size_t nchars)
|
||||
{
|
||||
// needed capacity in values
|
||||
std::size_t const needed =
|
||||
size() +
|
||||
1 +
|
||||
((chars_ + nchars +
|
||||
sizeof(value) - 1) /
|
||||
sizeof(value));
|
||||
std::size_t const capacity =
|
||||
end_ - begin_;
|
||||
BOOST_ASSERT(
|
||||
needed > capacity);
|
||||
std::size_t new_cap = min_size_;
|
||||
// VFALCO check overflow here
|
||||
while(new_cap < needed)
|
||||
new_cap <<= 1;
|
||||
auto const begin =
|
||||
reinterpret_cast<value*>(
|
||||
sp_->allocate(
|
||||
new_cap * sizeof(value)));
|
||||
std::size_t const cur_size = top_ - begin_;
|
||||
if(begin_)
|
||||
{
|
||||
std::size_t amount =
|
||||
size() * sizeof(value);
|
||||
if(chars_ > 0)
|
||||
amount += sizeof(value) + chars_;
|
||||
std::memcpy(
|
||||
reinterpret_cast<char*>(begin),
|
||||
reinterpret_cast<char*>(begin_),
|
||||
amount);
|
||||
if(begin_ != temp_)
|
||||
sp_->deallocate(begin_,
|
||||
capacity * sizeof(value));
|
||||
}
|
||||
// book-keeping
|
||||
top_ = begin + cur_size;
|
||||
end_ = begin + new_cap;
|
||||
begin_ = begin;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
void
|
||||
value_stack::
|
||||
stack::
|
||||
append(string_view s)
|
||||
{
|
||||
std::size_t const bytes_avail =
|
||||
reinterpret_cast<
|
||||
char const*>(end_) -
|
||||
reinterpret_cast<
|
||||
char const*>(top_);
|
||||
// make sure there is room for
|
||||
// pushing one more value without
|
||||
// clobbering the string.
|
||||
if(sizeof(value) + chars_ +
|
||||
s.size() > bytes_avail)
|
||||
grow(s.size());
|
||||
|
||||
// copy the new piece
|
||||
std::memcpy(
|
||||
reinterpret_cast<char*>(
|
||||
top_ + 1) + chars_,
|
||||
s.data(), s.size());
|
||||
chars_ += s.size();
|
||||
|
||||
// ensure a pushed value cannot
|
||||
// clobber the released string.
|
||||
BOOST_ASSERT(
|
||||
reinterpret_cast<char*>(
|
||||
top_ + 1) + chars_ <=
|
||||
reinterpret_cast<char*>(
|
||||
end_));
|
||||
}
|
||||
|
||||
string_view
|
||||
value_stack::
|
||||
stack::
|
||||
release_string() noexcept
|
||||
{
|
||||
// ensure a pushed value cannot
|
||||
// clobber the released string.
|
||||
BOOST_ASSERT(
|
||||
reinterpret_cast<char*>(
|
||||
top_ + 1) + chars_ <=
|
||||
reinterpret_cast<char*>(
|
||||
end_));
|
||||
auto const n = chars_;
|
||||
chars_ = 0;
|
||||
return { reinterpret_cast<
|
||||
char const*>(top_ + 1), n };
|
||||
}
|
||||
|
||||
// transfer ownership of the top n
|
||||
// elements of the stack to the caller
|
||||
value*
|
||||
value_stack::
|
||||
stack::
|
||||
release(std::size_t n) noexcept
|
||||
{
|
||||
BOOST_ASSERT(n <= size());
|
||||
BOOST_ASSERT(chars_ == 0);
|
||||
top_ -= n;
|
||||
return top_;
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
value&
|
||||
value_stack::
|
||||
stack::
|
||||
push(Args&&... args)
|
||||
{
|
||||
BOOST_ASSERT(chars_ == 0);
|
||||
if(top_ >= end_)
|
||||
grow_one();
|
||||
value& jv = detail::access::
|
||||
construct_value(top_,
|
||||
std::forward<Args>(args)...);
|
||||
++top_;
|
||||
return jv;
|
||||
}
|
||||
|
||||
template<class Unchecked>
|
||||
void
|
||||
value_stack::
|
||||
stack::
|
||||
exchange(Unchecked&& u)
|
||||
{
|
||||
BOOST_ASSERT(chars_ == 0);
|
||||
union U
|
||||
{
|
||||
value v;
|
||||
U() {}
|
||||
~U() {}
|
||||
} jv;
|
||||
// construct value on the stack
|
||||
// to avoid clobbering top_[0],
|
||||
// which belongs to `u`.
|
||||
detail::access::
|
||||
construct_value(
|
||||
&jv.v, std::move(u));
|
||||
std::memcpy(
|
||||
reinterpret_cast<
|
||||
char*>(top_),
|
||||
&jv.v, sizeof(value));
|
||||
++top_;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
value_stack::
|
||||
~value_stack()
|
||||
{
|
||||
// default dtor is here so the
|
||||
// definition goes in the library
|
||||
// instead of the caller's TU.
|
||||
}
|
||||
|
||||
value_stack::
|
||||
value_stack(
|
||||
storage_ptr sp,
|
||||
unsigned char* temp_buffer,
|
||||
std::size_t temp_size) noexcept
|
||||
: st_(
|
||||
std::move(sp),
|
||||
temp_buffer,
|
||||
temp_size)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
reset(storage_ptr sp) noexcept
|
||||
{
|
||||
st_.clear();
|
||||
|
||||
sp_.~storage_ptr();
|
||||
::new(&sp_) storage_ptr(
|
||||
pilfer(sp));
|
||||
|
||||
// `stack` needs this
|
||||
// to clean up correctly
|
||||
st_.run_dtors(
|
||||
! sp_.is_not_shared_and_deallocate_is_trivial());
|
||||
}
|
||||
|
||||
value
|
||||
value_stack::
|
||||
release() noexcept
|
||||
{
|
||||
// This means the caller did not
|
||||
// cause a single top level element
|
||||
// to be produced.
|
||||
BOOST_ASSERT(st_.size() == 1);
|
||||
|
||||
// give up shared ownership
|
||||
sp_ = {};
|
||||
|
||||
return pilfer(*st_.release(1));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_array(std::size_t n)
|
||||
{
|
||||
// we already have room if n > 0
|
||||
if(BOOST_JSON_UNLIKELY(n == 0))
|
||||
st_.maybe_grow();
|
||||
detail::unchecked_array ua(
|
||||
st_.release(n), n, sp_);
|
||||
st_.exchange(std::move(ua));
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_object(std::size_t n)
|
||||
{
|
||||
// we already have room if n > 0
|
||||
if(BOOST_JSON_UNLIKELY(n == 0))
|
||||
st_.maybe_grow();
|
||||
detail::unchecked_object uo(
|
||||
st_.release(n * 2), n, sp_);
|
||||
st_.exchange(std::move(uo));
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_chars(
|
||||
string_view s)
|
||||
{
|
||||
st_.append(s);
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_key(
|
||||
string_view s)
|
||||
{
|
||||
if(! st_.has_chars())
|
||||
{
|
||||
st_.push(detail::key_t{}, s, sp_);
|
||||
return;
|
||||
}
|
||||
auto part = st_.release_string();
|
||||
st_.push(detail::key_t{}, part, s, sp_);
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_string(
|
||||
string_view s)
|
||||
{
|
||||
if(! st_.has_chars())
|
||||
{
|
||||
// fast path
|
||||
st_.push(s, sp_);
|
||||
return;
|
||||
}
|
||||
|
||||
// VFALCO We could add a special
|
||||
// private ctor to string that just
|
||||
// creates uninitialized space,
|
||||
// to reduce member function calls.
|
||||
auto part = st_.release_string();
|
||||
auto& str = st_.push(
|
||||
string_kind, sp_).get_string();
|
||||
str.reserve(
|
||||
part.size() + s.size());
|
||||
std::memcpy(
|
||||
str.data(),
|
||||
part.data(), part.size());
|
||||
std::memcpy(
|
||||
str.data() + part.size(),
|
||||
s.data(), s.size());
|
||||
str.grow(part.size() + s.size());
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_int64(
|
||||
int64_t i)
|
||||
{
|
||||
st_.push(i, sp_);
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_uint64(
|
||||
uint64_t u)
|
||||
{
|
||||
st_.push(u, sp_);
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_double(
|
||||
double d)
|
||||
{
|
||||
st_.push(d, sp_);
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_bool(
|
||||
bool b)
|
||||
{
|
||||
st_.push(b, sp_);
|
||||
}
|
||||
|
||||
void
|
||||
value_stack::
|
||||
push_null()
|
||||
{
|
||||
st_.push(nullptr, sp_);
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_VISIT_HPP
|
||||
#define BOOST_JSON_IMPL_VISIT_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template<class Visitor>
|
||||
auto
|
||||
visit(
|
||||
Visitor&& v,
|
||||
value& jv) -> decltype(
|
||||
std::declval<Visitor>()(nullptr))
|
||||
{
|
||||
switch(jv.kind())
|
||||
{
|
||||
default: // unreachable()?
|
||||
case kind::null: return std::forward<Visitor>(v)(nullptr);
|
||||
case kind::bool_: return std::forward<Visitor>(v)(jv.get_bool());
|
||||
case kind::int64: return std::forward<Visitor>(v)(jv.get_int64());
|
||||
case kind::uint64: return std::forward<Visitor>(v)(jv.get_uint64());
|
||||
case kind::double_: return std::forward<Visitor>(v)(jv.get_double());
|
||||
case kind::string: return std::forward<Visitor>(v)(jv.get_string());
|
||||
case kind::array: return std::forward<Visitor>(v)(jv.get_array());
|
||||
case kind::object: return std::forward<Visitor>(v)(jv.get_object());
|
||||
}
|
||||
}
|
||||
|
||||
template<class Visitor>
|
||||
auto
|
||||
visit(
|
||||
Visitor&& v,
|
||||
value const& jv) -> decltype(
|
||||
std::declval<Visitor>()(nullptr))
|
||||
{
|
||||
switch (jv.kind())
|
||||
{
|
||||
default: // unreachable()?
|
||||
case kind::null: return std::forward<Visitor>(v)(nullptr);
|
||||
case kind::bool_: return std::forward<Visitor>(v)(jv.get_bool());
|
||||
case kind::int64: return std::forward<Visitor>(v)(jv.get_int64());
|
||||
case kind::uint64: return std::forward<Visitor>(v)(jv.get_uint64());
|
||||
case kind::double_: return std::forward<Visitor>(v)(jv.get_double());
|
||||
case kind::string: return std::forward<Visitor>(v)(jv.get_string());
|
||||
case kind::array: return std::forward<Visitor>(v)(jv.get_array());
|
||||
case kind::object: return std::forward<Visitor>(v)(jv.get_object());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
|
||||
<Type Name="boost::json::storage_ptr">
|
||||
<DisplayString Condition="i_==0">default</DisplayString>
|
||||
<DisplayString Condition="(i_&3)==1"> shared</DisplayString>
|
||||
<DisplayString Condition="(i_&3)==2"> trivial</DisplayString>
|
||||
<DisplayString Condition="(i_&3)==3"> shared, trivial</DisplayString>
|
||||
<DisplayString>non-owning</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[ refs ]" Condition="(i_&1)==1">((shared_resource*)(i_&~3))->refs</Item>
|
||||
<Item Name="[ resource ]" Condition="(i_&2)==1">(shared_resource*)(i_&~3)</Item>
|
||||
<Item Name="[ resource ]" Condition="(i_&2)!=1">(memory_resource*)(i_&~3)</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::detail::shared_resource_impl<*>">
|
||||
<DisplayString>$T1*</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[ refs ]">refs</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::monotonic_resource">
|
||||
<DisplayString>monotonic_resource</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[ free ]">head_->n</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::static_resource">
|
||||
<DisplayString>static_resource</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[ free ]">n_</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::value">
|
||||
<DisplayString Condition="sca_.k==kind::null">null</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::bool_">{sca_.b}</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::int64">{sca_.i}</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::uint64">{sca_.u}u</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::double_">{sca_.d}</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::string">{((char*)(str_.impl_.p_.t+1)),[str_.impl_.p_.t->size]s}</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::string+64">{((char*)(str_.impl_.k_.s)),[str_.impl_.k_.n]s}:</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::string+128">{str_.impl_.s_.buf,[detail::string_impl::sbo_chars_-str_.impl_.s_.buf[detail::string_impl::sbo_chars_]]s}</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::array">array [{arr_.t_->size}]</DisplayString>
|
||||
<DisplayString Condition="sca_.k==kind::object">object [{obj_.t_->size}]</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="sca_.k==kind::string">str_</ExpandedItem>
|
||||
<ExpandedItem Condition="sca_.k==kind::string+64">str_</ExpandedItem>
|
||||
<ExpandedItem Condition="sca_.k==kind::string+128">str_</ExpandedItem>
|
||||
<ExpandedItem Condition="sca_.k==kind::array">arr_</ExpandedItem>
|
||||
<ExpandedItem Condition="sca_.k==kind::object">obj_</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::string">
|
||||
<DisplayString Condition="impl_.s_.k==kind::string">{((char*)(impl_.p_.t+1)),[impl_.p_.t->size]s}</DisplayString>
|
||||
<DisplayString Condition="impl_.s_.k==kind::string+64">{((char*)(impl_.k_.s)),[impl_.k_.n]s}:</DisplayString>
|
||||
<DisplayString Condition="impl_.s_.k==kind::string+128">{impl_.s_.buf,[detail::string_impl::sbo_chars_-impl_.s_.buf[detail::string_impl::sbo_chars_]]s}</DisplayString>
|
||||
<Expand>
|
||||
<!-- VFALCO Need to handle key string here -->
|
||||
<Item Name="[size]">impl_.s_.k==kind::string?impl_.p_.t->size:detail::string_impl::sbo_chars_-impl_.s_.buf[detail::string_impl::sbo_chars_]</Item>
|
||||
<Item Name="[capacity]">impl_.s_.k==kind::string?impl_.p_.t->capacity:detail::string_impl::sbo_chars_</Item>
|
||||
<Item Name="[storage]">sp_</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::array">
|
||||
<DisplayString>array [{t_->size}]</DisplayString>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>t_->size</Size>
|
||||
<ValuePointer>((value*)(t_+1))</ValuePointer>
|
||||
</ArrayItems>
|
||||
<Item Name="[capacity]">t_->capacity</Item>
|
||||
<Item Name="[storage]">sp_</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::object">
|
||||
<DisplayString>object [{t_->size}]</DisplayString>
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>t_->size</Size>
|
||||
<ValuePointer>(boost::json::key_value_pair*)(t_+1)</ValuePointer>
|
||||
</ArrayItems>
|
||||
<Item Name="[capacity]">t_->capacity</Item>
|
||||
<Item Name="[storage]">sp_</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::json::key_value_pair">
|
||||
<DisplayString Condition="value_.sca_.k==kind::null">{{ {key_,[len_]s}, null }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::bool_">{{ {key_,[len_]s}, {value_.sca_.b} }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::int64">{{ {key_,[len_]s}, {value_.sca_.i} }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::uint64">{{ {key_,[len_]s}, {value_.sca_.u} }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::double_">{{ {key_,[len_]s}, {value_.sca_.d} }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::string">{{ {key_,[len_]s}, {((char*)(value_.str_.impl_.p_.t+1)),[value_.str_.impl_.p_.t->size]s} }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::string+128">{{ {key_,[len_]s}, {value_.str_.impl_.s_.buf,[detail::string_impl::sbo_chars_-value_.str_.impl_.s_.buf[detail::string_impl::sbo_chars_]]s} }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::array">{{ {key_,[len_]s}, array [{value_.arr_.t_->size}] }}</DisplayString>
|
||||
<DisplayString Condition="value_.sca_.k==kind::object">{{ {key_,[len_]s}, object [{value_.obj_.t_->size}] }}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>&this->value_</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
</AutoVisualizer>
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_KIND_HPP
|
||||
#define BOOST_JSON_KIND_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/string_view.hpp>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** Constants for identifying the type of a value
|
||||
|
||||
These values are returned from @ref value::kind
|
||||
*/
|
||||
// Order matters
|
||||
enum class kind : unsigned char
|
||||
{
|
||||
/// The null value.
|
||||
null,
|
||||
|
||||
/// A `bool`.
|
||||
bool_,
|
||||
|
||||
/// A `std::int64_t`
|
||||
int64,
|
||||
|
||||
/// A `std::uint64_t`
|
||||
uint64,
|
||||
|
||||
/// A `double`.
|
||||
double_,
|
||||
|
||||
/// A @ref string.
|
||||
string,
|
||||
|
||||
/// An @ref array.
|
||||
array,
|
||||
|
||||
/// An @ref object.
|
||||
object
|
||||
};
|
||||
|
||||
/** Return a string representing a kind.
|
||||
|
||||
This provides a human-readable string
|
||||
representing a @ref kind. This may be
|
||||
useful for diagnostics.
|
||||
|
||||
@returns The string.
|
||||
|
||||
@param k The kind.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
string_view
|
||||
to_string(kind k) noexcept;
|
||||
|
||||
/** Format a kind to an output stream.
|
||||
|
||||
This allows a @ref kind to be formatted as
|
||||
a string, typically for diagnostics.
|
||||
|
||||
@returns The output stream.
|
||||
|
||||
@param os The output stream to format to.
|
||||
|
||||
@param k The kind to format.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, kind k);
|
||||
|
||||
/** A tag type used to select a @ref value constructor overload.
|
||||
|
||||
The library provides the constant @ref array_kind
|
||||
which may be used to select the @ref value constructor
|
||||
that creates an empty @ref array.
|
||||
|
||||
@see @ref array_kind
|
||||
*/
|
||||
struct array_kind_t
|
||||
{
|
||||
};
|
||||
|
||||
/** A tag type used to select a @ref value constructor overload.
|
||||
|
||||
The library provides the constant @ref object_kind
|
||||
which may be used to select the @ref value constructor
|
||||
that creates an empty @ref object.
|
||||
|
||||
@see @ref object_kind
|
||||
*/
|
||||
struct object_kind_t
|
||||
{
|
||||
};
|
||||
|
||||
/** A tag type used to select a @ref value constructor overload.
|
||||
|
||||
The library provides the constant @ref string_kind
|
||||
which may be used to select the @ref value constructor
|
||||
that creates an empty @ref string.
|
||||
|
||||
@see @ref string_kind
|
||||
*/
|
||||
struct string_kind_t
|
||||
{
|
||||
};
|
||||
|
||||
/** A constant used to select a @ref value constructor overload.
|
||||
|
||||
The library provides this constant to allow efficient
|
||||
construction of a @ref value containing an empty @ref array.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
storage_ptr sp;
|
||||
value jv( array_kind, sp ); // sp is an optional parameter
|
||||
@endcode
|
||||
|
||||
@see @ref array_kind_t
|
||||
*/
|
||||
BOOST_JSON_INLINE_VARIABLE(array_kind, array_kind_t);
|
||||
|
||||
/** A constant used to select a @ref value constructor overload.
|
||||
|
||||
The library provides this constant to allow efficient
|
||||
construction of a @ref value containing an empty @ref object.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
storage_ptr sp;
|
||||
value jv( object_kind, sp ); // sp is an optional parameter
|
||||
@endcode
|
||||
|
||||
@see @ref object_kind_t
|
||||
*/
|
||||
BOOST_JSON_INLINE_VARIABLE(object_kind, object_kind_t);
|
||||
|
||||
/** A constant used to select a @ref value constructor overload.
|
||||
|
||||
The library provides this constant to allow efficient
|
||||
construction of a @ref value containing an empty @ref string.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
storage_ptr sp;
|
||||
value jv( string_kind, sp ); // sp is an optional parameter
|
||||
@endcode
|
||||
|
||||
@see @ref string_kind_t
|
||||
*/
|
||||
BOOST_JSON_INLINE_VARIABLE(string_kind, string_kind_t);
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_MEMORY_RESOURCE_HPP
|
||||
#define BOOST_JSON_MEMORY_RESOURCE_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
#include <boost/container/pmr/memory_resource.hpp>
|
||||
#include <boost/container/pmr/polymorphic_allocator.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
#ifdef BOOST_JSON_DOCS
|
||||
|
||||
/** The type of memory resource used by the library.
|
||||
|
||||
Alias for `boost::container::pmr::memory_resource`.
|
||||
*/
|
||||
class memory_resource
|
||||
{
|
||||
};
|
||||
|
||||
/** The type of polymorphic allocator used by the library.
|
||||
|
||||
Alias template for `boost::container::pmr::polymorphic_allocator`.
|
||||
*/
|
||||
template<class T>
|
||||
class polymorphic_allocator;
|
||||
|
||||
// VFALCO Bug: doc toolchain won't make this a ref
|
||||
//using memory_resource = __see_below__;
|
||||
|
||||
#else
|
||||
using memory_resource = boost::container::pmr::memory_resource;
|
||||
|
||||
template<class T>
|
||||
using polymorphic_allocator =
|
||||
boost::container::pmr::polymorphic_allocator<T>;
|
||||
#endif
|
||||
|
||||
/** Return true if a memory resource's deallocate function has no effect.
|
||||
|
||||
This metafunction may be specialized to indicate to
|
||||
the library that calls to the `deallocate` function of
|
||||
a @ref memory_resource have no effect. The implementation
|
||||
will elide such calls when it is safe to do so. By default,
|
||||
the implementation assumes that all memory resources
|
||||
require a call to `deallocate` for each memory region
|
||||
obtained by calling `allocate`.
|
||||
|
||||
@par Example
|
||||
|
||||
This example specializes the metafuction for `my_resource`,
|
||||
to indicate that calls to deallocate have no effect:
|
||||
|
||||
@code
|
||||
|
||||
// Forward-declaration for a user-defined memory resource
|
||||
struct my_resource;
|
||||
|
||||
// It is necessary to specialize the template from
|
||||
// inside the namespace in which it is declared:
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template<>
|
||||
struct is_deallocate_trivial< my_resource >
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
@endcode
|
||||
|
||||
It is usually not necessary for users to check this trait.
|
||||
Instead, they can call @ref storage_ptr::is_deallocate_trivial
|
||||
to determine if the pointed-to memory resource has a trivial
|
||||
deallocate function.
|
||||
|
||||
@see
|
||||
@ref memory_resource,
|
||||
@ref storage_ptr
|
||||
*/
|
||||
template<class T>
|
||||
struct is_deallocate_trivial
|
||||
{
|
||||
/** A bool equal to true if calls to `T::do_deallocate` have no effect.
|
||||
|
||||
The primary template sets `value` to false.
|
||||
*/
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_MONOTONIC_RESOURCE_HPP
|
||||
#define BOOST_JSON_MONOTONIC_RESOURCE_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/memory_resource.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4251) // class needs to have dll-interface to be used by clients of class
|
||||
#pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
/** A dynamically allocating resource with a trivial deallocate
|
||||
|
||||
This memory resource is a special-purpose resource
|
||||
that releases allocated memory only when the resource
|
||||
is destroyed (or when @ref release is called).
|
||||
It has a trivial deallocate function; that is, the
|
||||
metafunction @ref is_deallocate_trivial returns `true`.
|
||||
\n
|
||||
The resource can be constructed with an initial buffer.
|
||||
If there is no initial buffer, or if the buffer is
|
||||
exhausted, subsequent dynamic allocations are made from
|
||||
the system heap. The size of buffers obtained in this
|
||||
fashion follow a geometric progression.
|
||||
\n
|
||||
The purpose of this resource is to optimize the use
|
||||
case for performing many allocations, followed by
|
||||
deallocating everything at once. This is precisely the
|
||||
pattern of memory allocation which occurs when parsing:
|
||||
allocation is performed for each parsed element, and
|
||||
when the the resulting @ref value is no longer needed,
|
||||
the entire structure is destroyed. However, it is not
|
||||
suited for modifying the value after parsing is
|
||||
complete; reallocations waste memory, since the
|
||||
older buffer is not reclaimed until the resource
|
||||
is destroyed.
|
||||
|
||||
@par Example
|
||||
|
||||
This parses a JSON text into a value which uses a local
|
||||
stack buffer, then prints the result.
|
||||
|
||||
@code
|
||||
|
||||
unsigned char buf[ 4000 ];
|
||||
monotonic_resource mr( buf );
|
||||
|
||||
// Parse the string, using our memory resource
|
||||
auto const jv = parse( "[1,2,3]", &mr );
|
||||
|
||||
// Print the JSON
|
||||
std::cout << jv;
|
||||
|
||||
@endcode
|
||||
|
||||
@note The total amount of memory dynamically
|
||||
allocated is monotonically increasing; That is,
|
||||
it never decreases.
|
||||
|
||||
@par Thread Safety
|
||||
Members of the same instance may not be
|
||||
called concurrently.
|
||||
|
||||
@see
|
||||
https://en.wikipedia.org/wiki/Region-based_memory_management
|
||||
*/
|
||||
class
|
||||
BOOST_JSON_DECL
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
monotonic_resource final
|
||||
: public memory_resource
|
||||
{
|
||||
struct block;
|
||||
struct block_base
|
||||
{
|
||||
void* p;
|
||||
std::size_t avail;
|
||||
std::size_t size;
|
||||
block_base* next;
|
||||
};
|
||||
|
||||
block_base buffer_;
|
||||
block_base* head_ = &buffer_;
|
||||
std::size_t next_size_ = 1024;
|
||||
storage_ptr upstream_;
|
||||
|
||||
static constexpr std::size_t min_size_ = 1024;
|
||||
inline static constexpr std::size_t max_size();
|
||||
inline static std::size_t round_pow2(
|
||||
std::size_t n) noexcept;
|
||||
inline static std::size_t next_pow2(
|
||||
std::size_t n) noexcept;
|
||||
|
||||
public:
|
||||
/// Copy constructor (deleted)
|
||||
monotonic_resource(
|
||||
monotonic_resource const&) = delete;
|
||||
|
||||
/// Copy assignment (deleted)
|
||||
monotonic_resource& operator=(
|
||||
monotonic_resource const&) = delete;
|
||||
|
||||
/** Destructor
|
||||
|
||||
Deallocates all the memory owned by this resource.
|
||||
|
||||
@par Effects
|
||||
@code
|
||||
this->release();
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in the number of deallocations performed.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
~monotonic_resource();
|
||||
|
||||
/** Constructor
|
||||
|
||||
This constructs the resource and indicates
|
||||
that the first internal dynamic allocation
|
||||
shall be at least `initial_size` bytes.
|
||||
\n
|
||||
This constructor is guaranteed not to perform
|
||||
any dynamic allocations.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param initial_size The size of the first
|
||||
internal dynamic allocation. If this is lower
|
||||
than the implementation-defined lower limit, then
|
||||
the lower limit is used instead.
|
||||
|
||||
@param upstream An optional upstream memory resource
|
||||
to use for performing internal dynamic allocations.
|
||||
If this parameter is omitted, the default resource
|
||||
is used.
|
||||
*/
|
||||
explicit
|
||||
monotonic_resource(
|
||||
std::size_t initial_size = 1024,
|
||||
storage_ptr upstream = {}) noexcept;
|
||||
|
||||
/** Constructor
|
||||
|
||||
This constructs the resource and indicates that
|
||||
subsequent allocations should use the specified
|
||||
caller-owned buffer.
|
||||
When this buffer is exhausted, dynamic allocations
|
||||
from the upstream resource are made.
|
||||
\n
|
||||
This constructor is guaranteed not to perform
|
||||
any dynamic allocations.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param buffer The buffer to use.
|
||||
Ownership is not transferred; the caller is
|
||||
responsible for ensuring that the lifetime of
|
||||
the buffer extends until the resource is destroyed.
|
||||
|
||||
@param size The number of valid bytes pointed
|
||||
to by `buffer`.
|
||||
|
||||
@param upstream An optional upstream memory resource
|
||||
to use for performing internal dynamic allocations.
|
||||
If this parameter is omitted, the default resource
|
||||
is used.
|
||||
*/
|
||||
/** @{ */
|
||||
monotonic_resource(
|
||||
unsigned char* buffer,
|
||||
std::size_t size,
|
||||
storage_ptr upstream = {}) noexcept;
|
||||
|
||||
#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
|
||||
monotonic_resource(
|
||||
std::byte* buffer,
|
||||
std::size_t size,
|
||||
storage_ptr upstream) noexcept
|
||||
: monotonic_resource(reinterpret_cast<
|
||||
unsigned char*>(buffer), size,
|
||||
std::move(upstream))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/** Constructor
|
||||
|
||||
This constructs the resource and indicates that
|
||||
subsequent allocations should use the specified
|
||||
caller-owned buffer.
|
||||
When this buffer is exhausted, dynamic allocations
|
||||
from the upstream resource are made.
|
||||
\n
|
||||
This constructor is guaranteed not to perform
|
||||
any dynamic allocations.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param buffer The buffer to use.
|
||||
Ownership is not transferred; the caller is
|
||||
responsible for ensuring that the lifetime of
|
||||
the buffer extends until the resource is destroyed.
|
||||
|
||||
@param upstream An optional upstream memory resource
|
||||
to use for performing internal dynamic allocations.
|
||||
If this parameter is omitted, the default resource
|
||||
is used.
|
||||
*/
|
||||
/** @{ */
|
||||
template<std::size_t N>
|
||||
explicit
|
||||
monotonic_resource(
|
||||
unsigned char(&buffer)[N],
|
||||
storage_ptr upstream = {}) noexcept
|
||||
: monotonic_resource(&buffer[0],
|
||||
N, std::move(upstream))
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
|
||||
template<std::size_t N>
|
||||
explicit
|
||||
monotonic_resource(
|
||||
std::byte(&buffer)[N],
|
||||
storage_ptr upstream = {}) noexcept
|
||||
: monotonic_resource(&buffer[0],
|
||||
N, std::move(upstream))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
// Safety net for accidental buffer overflows
|
||||
template<std::size_t N>
|
||||
monotonic_resource(
|
||||
unsigned char(&buffer)[N],
|
||||
std::size_t n,
|
||||
storage_ptr upstream = {}) noexcept
|
||||
: monotonic_resource(&buffer[0],
|
||||
n, std::move(upstream))
|
||||
{
|
||||
// If this goes off, check your parameters
|
||||
// closely, chances are you passed an array
|
||||
// thinking it was a pointer.
|
||||
BOOST_ASSERT(n <= N);
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_byte
|
||||
// Safety net for accidental buffer overflows
|
||||
template<std::size_t N>
|
||||
monotonic_resource(
|
||||
std::byte(&buffer)[N],
|
||||
std::size_t n,
|
||||
storage_ptr upstream = {}) noexcept
|
||||
: monotonic_resource(&buffer[0],
|
||||
n, std::move(upstream))
|
||||
{
|
||||
// If this goes off, check your parameters
|
||||
// closely, chances are you passed an array
|
||||
// thinking it was a pointer.
|
||||
BOOST_ASSERT(n <= N);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Release all allocated memory.
|
||||
|
||||
This function deallocates all allocated memory.
|
||||
If an initial buffer was provided upon construction,
|
||||
then all of the bytes will be available again for
|
||||
allocation. Allocated memory is deallocated even
|
||||
if deallocate has not been called for some of
|
||||
the allocated blocks.
|
||||
|
||||
@par Complexity
|
||||
Linear in the number of deallocations performed.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
void
|
||||
release() noexcept;
|
||||
|
||||
protected:
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align) override;
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t align) override;
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept override;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct is_deallocate_trivial<
|
||||
monotonic_resource>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright (c) 2020 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_NULL_RESOURCE_HPP
|
||||
#define BOOST_JSON_NULL_RESOURCE_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/memory_resource.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** Return a pointer to the null resource.
|
||||
|
||||
This memory resource always throws the exception
|
||||
`std::bad_alloc` in calls to `allocate`.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
memory_resource*
|
||||
get_null_resource() noexcept;
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+1686
File diff suppressed because it is too large
Load Diff
+214
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_PARSE_HPP
|
||||
#define BOOST_JSON_PARSE_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/error.hpp>
|
||||
#include <boost/json/parse_options.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/string_view.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** Return parsed JSON as a @ref value.
|
||||
|
||||
This function parses an entire string in one
|
||||
step to produce a complete JSON object, returned
|
||||
as a @ref value. If the buffer does not contain a
|
||||
complete serialized JSON, an error occurs. In this
|
||||
case the returned value will be null, using the
|
||||
[default memory resource].
|
||||
|
||||
@par Complexity
|
||||
Linear in `s.size()`.
|
||||
|
||||
@par Exception Safety
|
||||
Strong guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
|
||||
@return A value representing the parsed JSON,
|
||||
or a null if any error occurred.
|
||||
|
||||
@param s The string to parse.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
|
||||
@param sp The memory resource that the new value and all
|
||||
of its elements will use. If this parameter is omitted,
|
||||
the [default memory resource] is used.
|
||||
|
||||
@param opt The options for the parser. If this parameter
|
||||
is omitted, the parser will accept only standard JSON.
|
||||
|
||||
@see
|
||||
@ref parse_options,
|
||||
@ref stream_parser.
|
||||
|
||||
[default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
|
||||
*/
|
||||
/** @{ */
|
||||
BOOST_JSON_DECL
|
||||
value
|
||||
parse(
|
||||
string_view s,
|
||||
error_code& ec,
|
||||
storage_ptr sp = {},
|
||||
parse_options const& opt = {});
|
||||
|
||||
BOOST_JSON_DECL
|
||||
value
|
||||
parse(
|
||||
string_view s,
|
||||
std::error_code& ec,
|
||||
storage_ptr sp = {},
|
||||
parse_options const& opt = {});
|
||||
/** @} */
|
||||
|
||||
/** Return parsed JSON as a @ref value.
|
||||
|
||||
This function parses an entire string in one
|
||||
step to produce a complete JSON object, returned
|
||||
as a @ref value. If the buffer does not contain a
|
||||
complete serialized JSON, an exception is thrown.
|
||||
|
||||
@par Complexity
|
||||
Linear in `s.size()`.
|
||||
|
||||
@par Exception Safety
|
||||
Strong guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
|
||||
@return A value representing the parsed
|
||||
JSON upon success.
|
||||
|
||||
@param s The string to parse.
|
||||
|
||||
@param sp The memory resource that the new value and all
|
||||
of its elements will use. If this parameter is omitted,
|
||||
the [default memory resource] is used.
|
||||
|
||||
@param opt The options for the parser. If this parameter
|
||||
is omitted, the parser will accept only standard JSON.
|
||||
|
||||
@throw system_error Thrown on failure.
|
||||
|
||||
@see
|
||||
@ref parse_options,
|
||||
@ref stream_parser.
|
||||
|
||||
[default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value
|
||||
parse(
|
||||
string_view s,
|
||||
storage_ptr sp = {},
|
||||
parse_options const& opt = {});
|
||||
|
||||
/** Return parsed JSON as a @ref value.
|
||||
|
||||
This function reads data from an input stream and parses it to produce a
|
||||
complete JSON entity, returned as a @ref value. If the stream does not
|
||||
contain a complete serialized JSON, or contains extra non-whitespace data,
|
||||
an error occurs. In this case the returned value will be `null`, using the
|
||||
[default memory resource].
|
||||
|
||||
@par Complexity
|
||||
Linear in the size of consumed input.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
The stream may throw as described by
|
||||
[`std::ios::exceptions`](https://en.cppreference.com/w/cpp/io/basic_ios/exceptions).
|
||||
|
||||
@return A value representing the parsed JSON,
|
||||
or a `null` if any error occurred.
|
||||
|
||||
@param is The stream to read from.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
|
||||
@param sp The memory resource that the new value and all of its elements
|
||||
will use. If this parameter is omitted, the [default memory resource]
|
||||
is used.
|
||||
|
||||
@param opt The options for the parser. If this parameter is omitted, the
|
||||
parser will accept only standard JSON.
|
||||
|
||||
@see @ref parse_options, @ref stream_parser, @ref value::operator>>.
|
||||
|
||||
[default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
|
||||
*/
|
||||
/** @{ */
|
||||
BOOST_JSON_DECL
|
||||
value
|
||||
parse(
|
||||
std::istream& is,
|
||||
error_code& ec,
|
||||
storage_ptr sp = {},
|
||||
parse_options const& opt = {});
|
||||
|
||||
BOOST_JSON_DECL
|
||||
value
|
||||
parse(
|
||||
std::istream& is,
|
||||
std::error_code& ec,
|
||||
storage_ptr sp = {},
|
||||
parse_options const& opt = {});
|
||||
/** @} */
|
||||
|
||||
/** Return parsed JSON as a @ref value.
|
||||
|
||||
This function reads data from an input stream and parses it to produce a
|
||||
complete JSON entity, returned as a @ref value. If the stream does not
|
||||
contain a complete serialized JSON, or contains extra non-whitespace data,
|
||||
an exception is thrown.
|
||||
|
||||
@par Complexity
|
||||
Linear in the size of consumed input.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Throws @ref system_error on failed parse.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
The stream may throw as described by
|
||||
[`std::ios::exceptions`](https://en.cppreference.com/w/cpp/io/basic_ios/exceptions).
|
||||
|
||||
@return A value representing the parsed JSON upon success.
|
||||
|
||||
@param is The stream to read from.
|
||||
|
||||
@param sp The memory resource that the new value and all of its elements
|
||||
will use. If this parameter is omitted, the [default memory resource]
|
||||
is used.
|
||||
|
||||
@param opt The options for the parser. If this parameter is omitted, the
|
||||
parser will accept only standard JSON.
|
||||
|
||||
@see @ref parse_options, @ref stream_parser, @ref value::operator>>.
|
||||
|
||||
[default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value
|
||||
parse(
|
||||
std::istream& is,
|
||||
storage_ptr sp = {},
|
||||
parse_options const& opt = {});
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
//
|
||||
// Copyright (c) 2021 Peter Dimov
|
||||
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_PARSE_INTO_HPP
|
||||
#define BOOST_JSON_PARSE_INTO_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
|
||||
#include <boost/json/basic_parser.hpp>
|
||||
#include <boost/json/string_view.hpp>
|
||||
#include <boost/json/system_error.hpp>
|
||||
#include <boost/json/detail/parse_into.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** `basic_parser` that parses into a given type
|
||||
|
||||
This is an alias template for @ref basic_parser instantiations that use
|
||||
a dedicated handler that parses directly into an object provided by the
|
||||
user instead of creating a @ref value.
|
||||
|
||||
Objects of type `parser_for<T>` have constructor signature equivalent to
|
||||
`parser_for( parse_options const&, T& )`.
|
||||
|
||||
@tparam T the type to parse into. This type must be
|
||||
[*DefaultConstructible*](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
|
||||
*/
|
||||
template< class T >
|
||||
using parser_for =
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
basic_parser<detail::into_handler<T>>;
|
||||
#else
|
||||
__see_below__;
|
||||
#endif
|
||||
|
||||
/** Parse a JSON text into a user-defined object.
|
||||
|
||||
This function parses an entire string in one step and fills an object
|
||||
provided by the user. If the buffer does not contain a complete serialized
|
||||
JSON text, an error occurs. In this case `v` may be partially filled.
|
||||
|
||||
The function supports default constructible types satisfying
|
||||
<a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
|
||||
arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
|
||||
`std::optional`, `std::nullptr_t`, and structs and enums described using
|
||||
Boost.Describe.
|
||||
|
||||
@par Complexity
|
||||
Linear in `sv.size()`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
|
||||
@param v The type to parse into.
|
||||
|
||||
@param sv The string to parse.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
|
||||
@param opt The options for the parser. If this parameter
|
||||
is omitted, the parser will accept only standard JSON.
|
||||
*/
|
||||
/** @{ */
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
string_view sv,
|
||||
error_code& ec,
|
||||
parse_options const& opt = {} );
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
string_view sv,
|
||||
std::error_code& ec,
|
||||
parse_options const& opt = {} );
|
||||
/** @} */
|
||||
|
||||
/** Parse a JSON text into a user-defined object.
|
||||
|
||||
This function parses an entire string in one step and fills an object
|
||||
provided by the user. If the buffer does not contain a complete serialized
|
||||
JSON text, an exception is thrown. In this case `v` may be
|
||||
partially filled.
|
||||
|
||||
The function supports default constructible types satisfying
|
||||
<a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
|
||||
arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
|
||||
`std::optional`, `std::nullptr_t`, and structs and enums described using
|
||||
Boost.Describe.
|
||||
|
||||
@par Complexity
|
||||
Linear in `sv.size()`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Throws @ref system_error on failed parse.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
|
||||
@param v The type to parse into.
|
||||
|
||||
@param sv The string to parse.
|
||||
|
||||
@param opt The options for the parser. If this parameter
|
||||
is omitted, the parser will accept only standard JSON.
|
||||
*/
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
string_view sv,
|
||||
parse_options const& opt = {} );
|
||||
|
||||
/** Parse a JSON text into a user-defined object.
|
||||
|
||||
This function reads data from an input stream and fills an object provided
|
||||
by the user. If the buffer does not contain a complete serialized JSON
|
||||
text, or contains extra non-whitespace data, an error occurs. In this case
|
||||
`v` may be partially filled.
|
||||
|
||||
The function supports default constructible types satisfying
|
||||
<a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
|
||||
arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
|
||||
`std::optional`, `std::nullptr_t`, and structs and enums described using
|
||||
Boost.Describe.
|
||||
|
||||
@par Complexity
|
||||
Linear in the size of consumed input.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
The stream may throw as described by
|
||||
[`std::ios::exceptions`](https://en.cppreference.com/w/cpp/io/basic_ios/exceptions).
|
||||
|
||||
@param v The type to parse into.
|
||||
|
||||
@param is The stream to read from.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
|
||||
@param opt The options for the parser. If this parameter
|
||||
is omitted, the parser will accept only standard JSON.
|
||||
*/
|
||||
/** @{ */
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
std::istream& is,
|
||||
error_code& ec,
|
||||
parse_options const& opt = {} );
|
||||
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
std::istream& is,
|
||||
std::error_code& ec,
|
||||
parse_options const& opt = {} );
|
||||
/** @} */
|
||||
|
||||
/** Parse a JSON text into a user-defined object.
|
||||
|
||||
This function reads data from an input stream and fills an object provided
|
||||
by the user. If the buffer does not contain a complete serialized JSON
|
||||
text, or contains extra non-whitespace data, an exception is thrown. In
|
||||
this case `v` may be partially filled.
|
||||
|
||||
The function supports default constructible types satisfying
|
||||
<a href="https://en.cppreference.com/w/cpp/named_req/SequenceContainer"><em>SequenceContainer</em></a>,
|
||||
arrays, arithmetic types, `bool`, `std::tuple`, `std::pair`,
|
||||
`std::optional`, `std::nullptr_t`, and structs and enums described using
|
||||
Boost.Describe.
|
||||
|
||||
@par Complexity
|
||||
Linear in the size of consumed input.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Throws @ref system_error on failed parse.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
The stream may throw as described by
|
||||
[`std::ios::exceptions`](https://en.cppreference.com/w/cpp/io/basic_ios/exceptions).
|
||||
|
||||
@param v The type to parse into.
|
||||
|
||||
@param is The stream to read from.
|
||||
|
||||
@param opt The options for the parser. If this parameter
|
||||
is omitted, the parser will accept only standard JSON.
|
||||
*/
|
||||
template<class V>
|
||||
void
|
||||
parse_into(
|
||||
V& v,
|
||||
std::istream& is,
|
||||
parse_options const& opt = {} );
|
||||
|
||||
} // namespace boost
|
||||
} // namespace json
|
||||
|
||||
#include <boost/json/impl/parse_into.hpp>
|
||||
|
||||
#endif
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_PARSE_OPTIONS_HPP
|
||||
#define BOOST_JSON_PARSE_OPTIONS_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** Enumeration of number parsing modes
|
||||
|
||||
These values are used to select the way to parse numbers.
|
||||
|
||||
@see
|
||||
@ref parse_options,
|
||||
@ref basic_parser,
|
||||
@ref parser.
|
||||
*/
|
||||
enum class number_precision : unsigned char
|
||||
{
|
||||
/// Fast, but potentially less precise mode.
|
||||
imprecise,
|
||||
|
||||
/// Slower, but precise mode.
|
||||
precise,
|
||||
|
||||
/// The fastest mode, that only validates encountered numbers without
|
||||
/// parsing them.
|
||||
none,
|
||||
};
|
||||
|
||||
/** Parser options
|
||||
|
||||
This structure is used for specifying
|
||||
maximum parsing depth, and whether
|
||||
to allow various non-standard extensions.
|
||||
Default-constructed options set maximum
|
||||
parsing depth to 32 and specify that only
|
||||
standard JSON is allowed,
|
||||
|
||||
@see
|
||||
@ref basic_parser,
|
||||
@ref parser.
|
||||
*/
|
||||
struct parse_options
|
||||
{
|
||||
/** Maximum nesting level of arrays and objects.
|
||||
|
||||
This specifies the maximum number of nested
|
||||
structures allowed while parsing a JSON text. If
|
||||
this limit is exceeded during a parse, an
|
||||
error is returned.
|
||||
|
||||
@see
|
||||
@ref basic_parser,
|
||||
@ref stream_parser.
|
||||
*/
|
||||
std::size_t max_depth = 32;
|
||||
|
||||
/** Number pasing mode
|
||||
|
||||
This selects the way to parse numbers. The default is to parse them
|
||||
fast, but with possible slight imprecision for floating point numbers
|
||||
with larger mantissas. Users can also choose to parse numbers slower
|
||||
but with full precision. Or to not parse them at all, and only validate
|
||||
numbers. The latter mode is useful for @ref basic_parser instantiations
|
||||
that wish to treat numbers in a custom way.
|
||||
|
||||
@see
|
||||
@ref basic_parser,
|
||||
@ref stream_parser.
|
||||
*/
|
||||
number_precision numbers = number_precision::imprecise;
|
||||
|
||||
/** Non-standard extension option
|
||||
|
||||
Allow C and C++ style comments to appear
|
||||
anywhere that whitespace is permissible.
|
||||
|
||||
@see
|
||||
@ref basic_parser,
|
||||
@ref stream_parser.
|
||||
*/
|
||||
bool allow_comments = false;
|
||||
|
||||
/** Non-standard extension option
|
||||
|
||||
Allow a trailing comma to appear after
|
||||
the last element of any array or object.
|
||||
|
||||
@see
|
||||
@ref basic_parser,
|
||||
@ref stream_parser.
|
||||
*/
|
||||
bool allow_trailing_commas = false;
|
||||
|
||||
/** Non-standard extension option
|
||||
|
||||
Allow invalid UTF-8 sequnces to appear
|
||||
in keys and strings.
|
||||
|
||||
@note This increases parsing performance.
|
||||
|
||||
@see
|
||||
@ref basic_parser,
|
||||
@ref stream_parser.
|
||||
*/
|
||||
bool allow_invalid_utf8 = false;
|
||||
|
||||
/** Non-standard extension option
|
||||
|
||||
Allow `Infinity`, `-Infinity`, and `NaN` JSON literals. These values
|
||||
are produced by some popular JSON implementations for positive
|
||||
infinity, negative infinity and NaN special numbers respectively.
|
||||
|
||||
@see
|
||||
@ref basic_parser,
|
||||
@ref stream_parser.
|
||||
*/
|
||||
bool allow_infinity_and_nan = false;
|
||||
|
||||
/** Set JSON parse options on input stream.
|
||||
|
||||
The function stores parse options in the private storage of the stream. If
|
||||
the stream fails to allocate necessary private storage, `badbit` will be
|
||||
set on it.
|
||||
|
||||
@return Reference to `is`.
|
||||
|
||||
@par Complexity
|
||||
Amortized constant (due to potential memory allocation by the stream).
|
||||
|
||||
@par Exception Safety
|
||||
Strong guarantee.
|
||||
The stream may throw as configured by
|
||||
[`std::ios::exceptions`](https://en.cppreference.com/w/cpp/io/basic_ios/exceptions).
|
||||
|
||||
@param is The input stream.
|
||||
|
||||
@param opts The options to store.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
friend
|
||||
std::istream&
|
||||
operator>>( std::istream& is, parse_options const& opts );
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+829
@@ -0,0 +1,829 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_PARSER_HPP
|
||||
#define BOOST_JSON_PARSER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/basic_parser.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/detail/handler.hpp>
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
/** A DOM parser for JSON contained in a single buffer.
|
||||
|
||||
This class is used to parse a JSON text contained in a
|
||||
single character buffer, into a @ref value container.
|
||||
|
||||
@par Usage
|
||||
|
||||
To use the parser first construct it, then optionally
|
||||
call @ref reset to specify a @ref storage_ptr to use
|
||||
for the resulting @ref value. Then call @ref write
|
||||
to parse a character buffer containing a complete
|
||||
JSON text. If the parse is successful, call @ref release
|
||||
to take ownership of the value:
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write( "[1,2,3]" ); // parse a complete JSON text
|
||||
assert( n == 7 ); // all characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Extra Data
|
||||
|
||||
When the character buffer provided as input contains
|
||||
additional data that is not part of the complete
|
||||
JSON text, an error is returned. The @ref write_some
|
||||
function is an alternative which allows the parse
|
||||
to finish early, without consuming all the characters
|
||||
in the buffer. This allows parsing of a buffer
|
||||
containing multiple individual JSON texts or containing
|
||||
different protocol data:
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write_some( "[1,2,3] null" ); // parse a complete JSON text
|
||||
assert( n == 8 ); // only some characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Temporary Storage
|
||||
|
||||
The parser may dynamically allocate temporary
|
||||
storage as needed to accommodate the nesting level
|
||||
of the JSON text being parsed. Temporary storage is
|
||||
first obtained from an optional, caller-owned
|
||||
buffer specified upon construction. When that
|
||||
is exhausted, the next allocation uses the
|
||||
@ref memory_resource passed to the constructor; if
|
||||
no such argument is specified, the default memory
|
||||
resource is used. Temporary storage is freed only
|
||||
when the parser is destroyed; The performance of
|
||||
parsing multiple JSON texts may be improved by reusing
|
||||
the same parser instance.
|
||||
\n
|
||||
It is important to note that the @ref memory_resource
|
||||
supplied upon construction is used for temporary
|
||||
storage only, and not for allocating the elements
|
||||
which make up the parsed value. That other memory
|
||||
resource is optionally supplied in each call
|
||||
to @ref reset.
|
||||
|
||||
@par Duplicate Keys
|
||||
|
||||
If there are object elements with duplicate keys;
|
||||
that is, if multiple elements in an object have
|
||||
keys that compare equal, only the last equivalent
|
||||
element will be inserted.
|
||||
|
||||
@par Non-Standard JSON
|
||||
|
||||
The @ref parse_options structure optionally
|
||||
provided upon construction is used to customize
|
||||
some parameters of the parser, including which
|
||||
non-standard JSON extensions should be allowed.
|
||||
A default-constructed parse options allows only
|
||||
standard JSON.
|
||||
|
||||
@par Thread Safety
|
||||
|
||||
Distinct instances may be accessed concurrently.
|
||||
Non-const member functions of a shared instance
|
||||
may not be called concurrently with any other
|
||||
member functions of that instance.
|
||||
|
||||
@see
|
||||
@ref parse,
|
||||
@ref parse_options,
|
||||
@ref stream_parser.
|
||||
*/
|
||||
class parser
|
||||
{
|
||||
basic_parser<detail::handler> p_;
|
||||
|
||||
public:
|
||||
/// Copy constructor (deleted)
|
||||
parser(
|
||||
parser const&) = delete;
|
||||
|
||||
/// Copy assignment (deleted)
|
||||
parser& operator=(
|
||||
parser const&) = delete;
|
||||
|
||||
/** Destructor.
|
||||
|
||||
All dynamically allocated memory, including
|
||||
any incomplete parsing results, is freed.
|
||||
|
||||
@par Complexity
|
||||
Linear in the size of partial results
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
~parser() = default;
|
||||
|
||||
/** Constructor.
|
||||
|
||||
This constructs a new parser which first uses
|
||||
the caller-owned storage pointed to by `buffer`
|
||||
for temporary storage, falling back to the memory
|
||||
resource `sp` if needed. The parser will use the
|
||||
specified parsing options.
|
||||
\n
|
||||
The parsed value will use the default memory
|
||||
resource for storage. To use a different resource,
|
||||
call @ref reset after construction.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param sp The memory resource to use for
|
||||
temporary storage after `buffer` is exhausted.
|
||||
|
||||
@param opt The parsing options to use.
|
||||
|
||||
@param buffer A pointer to valid memory of at least
|
||||
`size` bytes for the parser to use for temporary storage.
|
||||
Ownership is not transferred, the caller is responsible
|
||||
for ensuring the lifetime of the memory pointed to by
|
||||
`buffer` extends until the parser is destroyed.
|
||||
|
||||
@param size The number of valid bytes in `buffer`.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
unsigned char* buffer,
|
||||
std::size_t size) noexcept;
|
||||
|
||||
/** Constructor.
|
||||
|
||||
This constructs a new parser which uses the default
|
||||
memory resource for temporary storage, and accepts
|
||||
only strict JSON.
|
||||
\n
|
||||
The parsed value will use the default memory
|
||||
resource for storage. To use a different resource,
|
||||
call @ref reset after construction.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
*/
|
||||
parser() noexcept
|
||||
: parser({}, {})
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor.
|
||||
|
||||
This constructs a new parser which uses the
|
||||
specified memory resource for temporary storage,
|
||||
and is configured to use the specified parsing
|
||||
options.
|
||||
\n
|
||||
The parsed value will use the default memory
|
||||
resource for storage. To use a different resource,
|
||||
call @ref reset after construction.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param sp The memory resource to use for temporary storage.
|
||||
|
||||
@param opt The parsing options to use.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt) noexcept;
|
||||
|
||||
/** Constructor.
|
||||
|
||||
This constructs a new parser which uses the
|
||||
specified memory resource for temporary storage,
|
||||
and accepts only strict JSON.
|
||||
\n
|
||||
The parsed value will use the default memory
|
||||
resource for storage. To use a different resource,
|
||||
call @ref reset after construction.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param sp The memory resource to use for temporary storage.
|
||||
*/
|
||||
explicit
|
||||
parser(storage_ptr sp) noexcept
|
||||
: parser(std::move(sp), {})
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor.
|
||||
|
||||
This constructs a new parser which first uses the
|
||||
caller-owned storage `buffer` for temporary storage,
|
||||
falling back to the memory resource `sp` if needed.
|
||||
The parser will use the specified parsing options.
|
||||
\n
|
||||
The parsed value will use the default memory
|
||||
resource for storage. To use a different resource,
|
||||
call @ref reset after construction.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param sp The memory resource to use for
|
||||
temporary storage after `buffer` is exhausted.
|
||||
|
||||
@param opt The parsing options to use.
|
||||
|
||||
@param buffer A buffer for the parser to use for
|
||||
temporary storage. Ownership is not transferred,
|
||||
the caller is responsible for ensuring the lifetime
|
||||
of `buffer` extends until the parser is destroyed.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
unsigned char(&buffer)[N]) noexcept
|
||||
: parser(std::move(sp),
|
||||
opt, &buffer[0], N)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
|
||||
/** Constructor.
|
||||
|
||||
This constructs a new parser which first uses
|
||||
the caller-owned storage pointed to by `buffer`
|
||||
for temporary storage, falling back to the memory
|
||||
resource `sp` if needed. The parser will use the
|
||||
specified parsing options.
|
||||
\n
|
||||
The parsed value will use the default memory
|
||||
resource for storage. To use a different resource,
|
||||
call @ref reset after construction.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param sp The memory resource to use for
|
||||
temporary storage after `buffer` is exhausted.
|
||||
|
||||
@param opt The parsing options to use.
|
||||
|
||||
@param buffer A pointer to valid memory of at least
|
||||
`size` bytes for the parser to use for temporary storage.
|
||||
Ownership is not transferred, the caller is responsible
|
||||
for ensuring the lifetime of the memory pointed to by
|
||||
`buffer` extends until the parser is destroyed.
|
||||
|
||||
@param size The number of valid bytes in `buffer`.
|
||||
*/
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
std::byte* buffer,
|
||||
std::size_t size) noexcept
|
||||
: parser(sp, opt, reinterpret_cast<
|
||||
unsigned char*>(buffer), size)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor.
|
||||
|
||||
This constructs a new parser which first uses the
|
||||
caller-owned storage `buffer` for temporary storage,
|
||||
falling back to the memory resource `sp` if needed.
|
||||
The parser will use the specified parsing options.
|
||||
\n
|
||||
The parsed value will use the default memory
|
||||
resource for storage. To use a different resource,
|
||||
call @ref reset after construction.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param sp The memory resource to use for
|
||||
temporary storage after `buffer` is exhausted.
|
||||
|
||||
@param opt The parsing options to use.
|
||||
|
||||
@param buffer A buffer for the parser to use for
|
||||
temporary storage. Ownership is not transferred,
|
||||
the caller is responsible for ensuring the lifetime
|
||||
of `buffer` extends until the parser is destroyed.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
std::byte(&buffer)[N]) noexcept
|
||||
: parser(std::move(sp),
|
||||
opt, &buffer[0], N)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
// Safety net for accidental buffer overflows
|
||||
template<std::size_t N>
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
unsigned char(&buffer)[N],
|
||||
std::size_t n) noexcept
|
||||
: parser(std::move(sp),
|
||||
opt, &buffer[0], n)
|
||||
{
|
||||
// If this goes off, check your parameters
|
||||
// closely, chances are you passed an array
|
||||
// thinking it was a pointer.
|
||||
BOOST_ASSERT(n <= N);
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_byte
|
||||
// Safety net for accidental buffer overflows
|
||||
template<std::size_t N>
|
||||
parser(
|
||||
storage_ptr sp,
|
||||
parse_options const& opt,
|
||||
std::byte(&buffer)[N], std::size_t n) noexcept
|
||||
: parser(std::move(sp),
|
||||
opt, &buffer[0], n)
|
||||
{
|
||||
// If this goes off, check your parameters
|
||||
// closely, chances are you passed an array
|
||||
// thinking it was a pointer.
|
||||
BOOST_ASSERT(n <= N);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Reset the parser for a new JSON text.
|
||||
|
||||
This function is used to reset the parser to
|
||||
prepare it for parsing a new complete JSON text.
|
||||
Any previous partial results are destroyed.
|
||||
|
||||
@par Complexity
|
||||
Constant or linear in the size of any previous
|
||||
partial parsing results.
|
||||
|
||||
@par Exception Safety
|
||||
No-throw guarantee.
|
||||
|
||||
@param sp A pointer to the @ref memory_resource
|
||||
to use for the resulting @ref value. The parser
|
||||
will acquire shared ownership.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
reset(storage_ptr sp = {}) noexcept;
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. Additional
|
||||
characters past the end of the complete JSON text
|
||||
are ignored. The function returns the actual
|
||||
number of characters parsed, which may be less
|
||||
than the size of the input. This allows parsing
|
||||
of a buffer containing multiple individual JSON texts
|
||||
or containing different protocol data:
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write_some( "[1,2,3] null" ); // parse a complete JSON text
|
||||
assert( n == 8 ); // only some characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param data A pointer to a buffer of `size`
|
||||
characters to parse.
|
||||
|
||||
@param size The number of characters pointed to
|
||||
by `data`.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
/** @{ */
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
std::error_code& ec);
|
||||
/** @} */
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. Additional
|
||||
characters past the end of the complete JSON text
|
||||
are ignored. The function returns the actual
|
||||
number of characters parsed, which may be less
|
||||
than the size of the input. This allows parsing
|
||||
of a buffer containing multiple individual JSON texts
|
||||
or containing different protocol data:
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write_some( "[1,2,3] null" ); // parse a complete JSON text
|
||||
assert( n == 8 ); // only some characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param data A pointer to a buffer of `size`
|
||||
characters to parse.
|
||||
|
||||
@param size The number of characters pointed to
|
||||
by `data`.
|
||||
|
||||
@throw system_error Thrown on error.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
write_some(
|
||||
char const* data,
|
||||
std::size_t size);
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. Additional
|
||||
characters past the end of the complete JSON text
|
||||
are ignored. The function returns the actual
|
||||
number of characters parsed, which may be less
|
||||
than the size of the input. This allows parsing
|
||||
of a buffer containing multiple individual JSON texts
|
||||
or containing different protocol data:
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write_some( "[1,2,3] null" ); // parse a complete JSON text
|
||||
assert( n == 8 ); // only some characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param s The character string to parse.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
/** @{ */
|
||||
std::size_t
|
||||
write_some(
|
||||
string_view s,
|
||||
error_code& ec)
|
||||
{
|
||||
return write_some(
|
||||
s.data(), s.size(), ec);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
write_some(
|
||||
string_view s,
|
||||
std::error_code& ec)
|
||||
{
|
||||
return write_some(
|
||||
s.data(), s.size(), ec);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. Additional
|
||||
characters past the end of the complete JSON text
|
||||
are ignored. The function returns the actual
|
||||
number of characters parsed, which may be less
|
||||
than the size of the input. This allows parsing
|
||||
of a buffer containing multiple individual JSON texts
|
||||
or containing different protocol data:
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write_some( "[1,2,3] null" ); // parse a complete JSON text
|
||||
assert( n == 8 ); // only some characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param s The character string to parse.
|
||||
|
||||
@throw system_error Thrown on error.
|
||||
*/
|
||||
std::size_t
|
||||
write_some(
|
||||
string_view s)
|
||||
{
|
||||
return write_some(
|
||||
s.data(), s.size());
|
||||
}
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. The entire
|
||||
buffer must be consumed; if there are additional
|
||||
characters past the end of the complete JSON text,
|
||||
the parse fails and an error is returned.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write( "[1,2,3]" ); // parse a complete JSON text
|
||||
assert( n == 7 ); // all characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param data A pointer to a buffer of `size`
|
||||
characters to parse.
|
||||
|
||||
@param size The number of characters pointed to
|
||||
by `data`.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
/** @{ */
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec);
|
||||
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
std::error_code& ec);
|
||||
/** @} */
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. The entire
|
||||
buffer must be consumed; if there are additional
|
||||
characters past the end of the complete JSON text,
|
||||
the parse fails and an error is returned.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write( "[1,2,3]" ); // parse a complete JSON text
|
||||
assert( n == 7 ); // all characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param data A pointer to a buffer of `size`
|
||||
characters to parse.
|
||||
|
||||
@param size The number of characters pointed to
|
||||
by `data`.
|
||||
|
||||
@throw system_error Thrown on error.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
std::size_t
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size);
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. The entire
|
||||
buffer must be consumed; if there are additional
|
||||
characters past the end of the complete JSON text,
|
||||
the parse fails and an error is returned.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write( "[1,2,3]" ); // parse a complete JSON text
|
||||
assert( n == 7 ); // all characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param s The character string to parse.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
/** @{ */
|
||||
std::size_t
|
||||
write(
|
||||
string_view s,
|
||||
error_code& ec)
|
||||
{
|
||||
return write(
|
||||
s.data(), s.size(), ec);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
write(
|
||||
string_view s,
|
||||
std::error_code& ec)
|
||||
{
|
||||
return write(
|
||||
s.data(), s.size(), ec);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Parse a buffer containing a complete JSON text.
|
||||
|
||||
This function parses a complete JSON text contained
|
||||
in the specified character buffer. The entire
|
||||
buffer must be consumed; if there are additional
|
||||
characters past the end of the complete JSON text,
|
||||
the parse fails and an error is returned.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
parser p; // construct a parser
|
||||
size_t n = p.write( "[1,2,3]" ); // parse a complete JSON text
|
||||
assert( n == 7 ); // all characters consumed
|
||||
value jv = p.release(); // take ownership of the value
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `size`.
|
||||
|
||||
@par Exception Safety
|
||||
Basic guarantee.
|
||||
Calls to `memory_resource::allocate` may throw.
|
||||
Upon error or exception, subsequent calls will
|
||||
fail until @ref reset is called to parse a new JSON text.
|
||||
|
||||
@return The number of characters consumed from
|
||||
the buffer.
|
||||
|
||||
@param s The character string to parse.
|
||||
|
||||
@throw system_error Thrown on error.
|
||||
*/
|
||||
std::size_t
|
||||
write(
|
||||
string_view s)
|
||||
{
|
||||
return write(
|
||||
s.data(), s.size());
|
||||
}
|
||||
|
||||
/** Return the parsed JSON text as a @ref value.
|
||||
|
||||
This returns the parsed value, or throws
|
||||
an exception if the parsing is incomplete or
|
||||
failed. It is necessary to call @ref reset
|
||||
after calling this function in order to parse
|
||||
another JSON text.
|
||||
|
||||
@par Complexity
|
||||
Constant.
|
||||
|
||||
@return The parsed value. Ownership of this
|
||||
value is transferred to the caller.
|
||||
|
||||
@throw system_error Thrown on failure.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
value
|
||||
release();
|
||||
};
|
||||
|
||||
} // namespace json
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_PILFER_HPP
|
||||
#define BOOST_JSON_PILFER_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
/*
|
||||
Implements "pilfering" from P0308R0
|
||||
|
||||
@see
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html
|
||||
*/
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** Tag wrapper to specify pilfer-construction.
|
||||
|
||||
This wrapper is used to specify a pilfer constructor
|
||||
overload.
|
||||
|
||||
@par Example
|
||||
|
||||
A pilfer constructor accepts a single argument
|
||||
of type @ref pilfered and throws nothing:
|
||||
|
||||
@code
|
||||
struct T
|
||||
{
|
||||
T( pilfered<T> ) noexcept;
|
||||
};
|
||||
@endcode
|
||||
|
||||
@note
|
||||
|
||||
The constructor should not be marked explicit.
|
||||
|
||||
@see @ref pilfer, @ref is_pilfer_constructible,
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html">
|
||||
Valueless Variants Considered Harmful</a>
|
||||
*/
|
||||
template<class T>
|
||||
class pilfered
|
||||
{
|
||||
T& t_;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
|
||||
Construct the wrapper from `t`.
|
||||
|
||||
@param t The pilferable object. Ownership
|
||||
is not transferred.
|
||||
*/
|
||||
explicit
|
||||
constexpr
|
||||
pilfered(T&& t) noexcept
|
||||
: t_(t)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return a reference to the pilferable object.
|
||||
|
||||
This returns a reference to the wrapped object.
|
||||
*/
|
||||
constexpr T&
|
||||
get() const noexcept
|
||||
{
|
||||
return t_;
|
||||
}
|
||||
|
||||
/** Return a pointer to the pilferable object.
|
||||
|
||||
This returns a pointer to the wrapped object.
|
||||
*/
|
||||
constexpr T*
|
||||
operator->() const noexcept
|
||||
{
|
||||
//return std::addressof(t_);
|
||||
return reinterpret_cast<T*>(
|
||||
const_cast<char *>(
|
||||
&reinterpret_cast<
|
||||
const volatile char &>(t_)));
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
// VFALCO Renamed this to work around an msvc bug
|
||||
namespace detail_pilfer {
|
||||
template<class>
|
||||
struct not_pilfered
|
||||
{
|
||||
};
|
||||
} // detail_pilfer
|
||||
#endif
|
||||
|
||||
/** Metafunction returning `true` if `T` is <em>PilferConstructible</em>
|
||||
|
||||
If `T` can be pilfer constructed, this metafunction is
|
||||
equal to `std::true_type`. Otherwise it is equal to
|
||||
`std::false_type`.
|
||||
|
||||
@see @ref pilfer, @ref pilfered,
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html">
|
||||
Valueless Variants Considered Harmful</a>
|
||||
*/
|
||||
template<class T>
|
||||
struct is_pilfer_constructible
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
: std::integral_constant<bool,
|
||||
std::is_nothrow_move_constructible<T>::value ||
|
||||
(
|
||||
std::is_nothrow_constructible<
|
||||
T, pilfered<T> >::value &&
|
||||
! std::is_nothrow_constructible<
|
||||
T, detail_pilfer::not_pilfered<T> >::value
|
||||
)>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
/** Indicate that an object `t` may be pilfered from.
|
||||
|
||||
A <em>pilfer</em> operation is the construction
|
||||
of a new object of type `T` from an existing
|
||||
object `t`. After the construction, the only
|
||||
valid operation on the pilfered-from object is
|
||||
destruction. This permits optimizations beyond
|
||||
those available for a move-construction, as the
|
||||
pilfered-from object is not required to be in
|
||||
a "usable" state.
|
||||
\n
|
||||
This is used similarly to `std::move`.
|
||||
|
||||
@par Example
|
||||
|
||||
A pilfer constructor accepts a single argument
|
||||
of type @ref pilfered and throws nothing:
|
||||
|
||||
@code
|
||||
struct T
|
||||
{
|
||||
T( pilfered<T> ) noexcept;
|
||||
};
|
||||
@endcode
|
||||
|
||||
Pilfer construction is performed using @ref pilfer :
|
||||
|
||||
@code
|
||||
{
|
||||
T t1; // default construction
|
||||
T t2( pilfer( t1 ) ); // pilfer-construct from t1
|
||||
|
||||
// At this point, t1 may only be destroyed
|
||||
}
|
||||
@endcode
|
||||
|
||||
@see @ref pilfered, @ref is_pilfer_constructible,
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html">
|
||||
Valueless Variants Considered Harmful</a>
|
||||
*/
|
||||
template<class T>
|
||||
auto
|
||||
pilfer(T&& t) noexcept ->
|
||||
typename std::conditional<
|
||||
std::is_nothrow_constructible<
|
||||
typename std::remove_reference<T>::type,
|
||||
pilfered<typename
|
||||
std::remove_reference<T>::type> >::value &&
|
||||
! std::is_nothrow_constructible<
|
||||
typename std::remove_reference<T>::type,
|
||||
detail_pilfer::not_pilfered<typename
|
||||
std::remove_reference<T>::type> >::value,
|
||||
pilfered<typename std::remove_reference<T>::type>,
|
||||
typename std::remove_reference<T>::type&&
|
||||
>::type
|
||||
{
|
||||
using U =
|
||||
typename std::remove_reference<T>::type;
|
||||
static_assert(
|
||||
is_pilfer_constructible<U>::value, "");
|
||||
return typename std::conditional<
|
||||
std::is_nothrow_constructible<
|
||||
U, pilfered<U> >::value &&
|
||||
! std::is_nothrow_constructible<
|
||||
U, detail_pilfer::not_pilfered<U> >::value,
|
||||
pilfered<U>, U&&
|
||||
>::type(std::move(t));
|
||||
}
|
||||
|
||||
/*
|
||||
template<class T>
|
||||
void
|
||||
relocate(T* dest, T& src) noexcept
|
||||
{
|
||||
static_assert(
|
||||
is_pilfer_constructible<T>::value, "");
|
||||
::new(dest) T(pilfer(src));
|
||||
src.~T();
|
||||
}
|
||||
*/
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user