feat():initial version

This commit is contained in:
2026-06-09 20:16:47 +08:00
commit 85fbb3188c
14809 changed files with 3044607 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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/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>
/* VFALCO NOTE
This file is in the detail namespace because it
is not allowed to be included directly by users,
who should be including <boost/json/basic_parser.hpp>
instead, which provides the member function definitions.
The source code is arranged this way to keep compile
times down.
*/
BOOST_JSON_NS_BEGIN
/** 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.
@headerfile <boost/json/basic_parser.hpp>
*/
template<class Handler>
class basic_parser
{
enum class state : char
{
doc1, doc2, doc3, doc4,
com1, com2, com3, com4,
nul1, nul2, nul3,
tru1, tru2, tru3,
fal1, fal2, fal3, fal4,
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
};
struct number
{
uint64_t mant;
int bias;
int exp;
bool frac;
bool neg;
};
// 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_;
parse_options opt_;
// how many levels deeper the parser can go
std::size_t depth_ = opt_.max_depth;
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) 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 StackEmpty_, bool AllowComments_/*,
bool AllowTrailing_, bool AllowBadUTF8_*/>
const char* resume_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 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<bool StackEmpty_>
const char* parse_null(const char* p,
std::integral_constant<bool, StackEmpty_> stack_empty);
template<bool StackEmpty_>
const char* parse_true(const char* p,
std::integral_constant<bool, StackEmpty_> stack_empty);
template<bool StackEmpty_>
const char* parse_false(const char* p,
std::integral_constant<bool, StackEmpty_> stack_empty);
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_>
const char* parse_number(const char* p,
std::integral_constant<bool, StackEmpty_> stack_empty,
std::integral_constant<char, First_> first);
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);
};
BOOST_JSON_NS_END
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
//
// 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_ALIGN_HPP
#define BOOST_JSON_DETAIL_ALIGN_HPP
#ifndef BOOST_JSON_STANDALONE
#include <boost/align/align.hpp>
#else
#include <cstddef>
#include <memory>
#endif
BOOST_JSON_NS_BEGIN
namespace detail {
#ifndef BOOST_JSON_STANDALONE
using boost::alignment::align;
// VFALCO workaround until Boost.Align has the type
struct class_type {};
enum unscoped_enumeration_type { };
enum class scoped_enumeration_type { };
// [support.types] p5: The type max_align_t is a trivial
// standard-layout type whose alignment requirement
// is at least as great as that of every scalar type.
struct max_align_t
{
// arithmetic types
char a;
char16_t b;
char32_t c;
bool d;
short int e;
int f;
long int g;
long long int h;
wchar_t i;
float j;
double k;
long double l;
// enumeration types
unscoped_enumeration_type m;
scoped_enumeration_type n;
// pointer types
void* o;
char* p;
class_type* q;
unscoped_enumeration_type* r;
scoped_enumeration_type* s;
void(*t)();
// pointer to member types
char class_type::* u;
void (class_type::*v)();
// nullptr
std::nullptr_t w;
};
#else
using std::align;
using max_align_t = std::max_align_t;
#endif
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,75 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
// includes are at the bottom of <boost/json/value.hpp>
#endif

View File

@@ -0,0 +1,144 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,321 @@
//
// 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
#ifndef BOOST_JSON_STANDALONE
# include <boost/config.hpp>
# include <boost/assert.hpp>
# include <boost/throw_exception.hpp>
#else
# include <cassert>
#endif
#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
#ifdef BOOST_JSON_STANDALONE
# define BOOST_JSON_NS_BEGIN \
namespace boost { \
namespace json { \
inline namespace standalone {
# define BOOST_JSON_NS_END } } }
#elif ! defined(BOOST_JSON_DOCS)
# define BOOST_JSON_NS_BEGIN \
namespace boost { \
namespace json {
# define BOOST_JSON_NS_END } }
#endif
#ifndef BOOST_JSON_STANDALONE
# 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
# define BOOST_JSON_CLASS_DECL BOOST_SYMBOL_EXPORT
# define BOOST_JSON_BUILD_DLL
# else
# define BOOST_JSON_DECL BOOST_SYMBOL_IMPORT
# define BOOST_JSON_CLASS_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
#else
// For standalone, shared library builds, users must manually
// define the macros BOOST_JSON_DECL and BOOST_JSON_CLASS_DECL
#endif
#ifndef BOOST_JSON_DECL
#define BOOST_JSON_DECL
#endif
#ifndef BOOST_JSON_CLASS_DECL
#define BOOST_JSON_CLASS_DECL
#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
# define BOOST_JSON_UNREACHABLE() static_cast<void>(0)
# ifdef _MSC_VER
# undef BOOST_JSON_UNREACHABLE
# define BOOST_JSON_UNREACHABLE() __assume(0)
# elif defined(__has_builtin)
# if __has_builtin(__builtin_unreachable)
# undef BOOST_JSON_UNREACHABLE
# define BOOST_JSON_UNREACHABLE() __builtin_unreachable()
# endif
# 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
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,99 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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_CLASS_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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,40 @@
//
// 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
BOOST_JSON_NS_BEGIN
namespace detail {
// Calculate salted digest of string
inline
std::size_t
digest(
char const* s,
std::size_t n,
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(;n--;++s)
hash = (*s ^ hash) * prime;
return hash;
}
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -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_EXCEPT_HPP
#define BOOST_JSON_DETAIL_EXCEPT_HPP
#include <boost/json/error.hpp>
#ifndef BOOST_JSON_STANDALONE
#include <boost/version.hpp>
#if BOOST_VERSION >= 107300
# include <boost/assert/source_location.hpp>
#endif
#include <boost/exception/diagnostic_information.hpp>
#endif
BOOST_JSON_NS_BEGIN
namespace detail {
// VFALCO we are supporting Boost 1.67 because it is in a lot of distros
#if ! defined(BOOST_JSON_STANDALONE) && defined(BOOST_CURRENT_LOCATION)
using source_location = boost::source_location;
#else
# define BOOST_CURRENT_LOCATION {}
struct source_location{};
#endif
BOOST_JSON_DECL void BOOST_NORETURN throw_bad_alloc(source_location const& loc);
BOOST_JSON_DECL void BOOST_NORETURN throw_invalid_argument(char const* what, source_location const& loc);
BOOST_JSON_DECL void BOOST_NORETURN throw_length_error(char const* what, source_location const& loc);
BOOST_JSON_DECL void BOOST_NORETURN throw_out_of_range(source_location const& loc);
BOOST_JSON_DECL void BOOST_NORETURN throw_system_error(error_code const& ec, source_location const& loc);
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -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_FORMAT_HPP
#define BOOST_JSON_DETAIL_FORMAT_HPP
BOOST_JSON_NS_BEGIN
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) noexcept;
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,66 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -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_IMPL_ARRAY_HPP
#define BOOST_JSON_DETAIL_IMPL_ARRAY_HPP
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,66 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,126 @@
//
// 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>
#ifndef BOOST_JSON_STANDALONE
# include <boost/version.hpp>
# include <boost/throw_exception.hpp>
#elif defined(BOOST_JSON_STANDALONE) && defined(BOOST_NO_EXCEPTIONS)
# include <exception>
#endif
#include <stdexcept>
#if defined(BOOST_JSON_STANDALONE)
namespace boost {
#if defined(BOOST_NO_EXCEPTIONS)
// When exceptions are disabled
// in standalone, you must provide
// this function.
BOOST_NORETURN
void
throw_exception(std::exception const&);
#endif
} // boost
#endif
BOOST_JSON_NS_BEGIN
namespace detail {
#if defined(BOOST_JSON_STANDALONE) && \
! defined(BOOST_NO_EXCEPTIONS)
// this is in the json namespace to avoid
// colliding with boost::throw_exception
template<class E>
void
BOOST_NORETURN
throw_exception(E e)
{
throw e;
}
#endif
void
throw_bad_alloc(
source_location const& loc)
{
(void)loc;
throw_exception(
std::bad_alloc()
#if BOOST_VERSION >= 107300
, loc
#endif
);
}
void
throw_length_error(
char const* what,
source_location const& loc)
{
(void)loc;
throw_exception(
std::length_error(what)
#if BOOST_VERSION >= 107300
, loc
#endif
);
}
void
throw_invalid_argument(
char const* what,
source_location const& loc)
{
(void)loc;
throw_exception(
std::invalid_argument(what)
#if BOOST_VERSION >= 107300
, loc
#endif
);
}
void
throw_out_of_range(
source_location const& loc)
{
(void)loc;
throw_exception(
std::out_of_range(
"out of range")
#if BOOST_VERSION >= 107300
, loc
#endif
);
}
void
throw_system_error(
error_code const& ec,
source_location const& loc)
{
(void)loc;
throw_exception(
system_error(ec)
#if BOOST_VERSION >= 107300
, loc
#endif
);
}
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,123 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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) noexcept
{
return static_cast<int>(
ryu::d2s_buffered_n(d, dest));
}
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,202 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,35 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,47 @@
//
// 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>
BOOST_JSON_NS_BEGIN
namespace detail {
stack::
~stack()
{
if(buf_)
sp_->deallocate(
buf_, cap_);
}
void
stack::
reserve(std::size_t n)
{
if(cap_ >= n)
return;
auto const buf = static_cast<
char*>(sp_->allocate(n));
if(buf_)
{
if(size_ > 0)
std::memcpy(buf, buf_, size_);
sp_->deallocate(buf_, cap_);
}
buf_ = buf;
cap_ = n;
}
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,471 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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())
detail::throw_length_error(
"string too large",
BOOST_CURRENT_LOCATION);
// 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())
detail::throw_length_error(
"string too large",
BOOST_CURRENT_LOCATION);
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)
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
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)
detail::throw_length_error(
"string too large",
BOOST_CURRENT_LOCATION);
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)
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
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)
detail::throw_length_error(
"string too large",
BOOST_CURRENT_LOCATION);
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)
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
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)
detail::throw_length_error(
"string too large",
BOOST_CURRENT_LOCATION);
// 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)
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
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)
detail::throw_length_error(
"string too large",
BOOST_CURRENT_LOCATION);
// 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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,79 @@
//
// 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 <cstdlib>
BOOST_JSON_NS_BEGIN
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;
}
};
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,118 @@
// 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>
BOOST_JSON_NS_BEGIN
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 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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,262 @@
// 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
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,363 @@
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,229 @@
// 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
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,59 @@
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,743 @@
// 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>
BOOST_JSON_NS_BEGIN
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) 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)) {
return copy_special_str(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);
}
void
d2s_buffered(
double f,
char* result) noexcept
{
const int index = d2s_buffered_n(f, result);
// Terminate the string.
result[index] = '\0';
}
char*
d2s(double f) noexcept
{
static thread_local char result[25];
d2s_buffered(f, result);
return result;
}
} // ryu
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,46 @@
// 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>
BOOST_JSON_NS_BEGIN
namespace detail {
namespace ryu {
BOOST_JSON_DECL
int d2s_buffered_n(double f, char* result) noexcept;
BOOST_JSON_DECL
void d2s_buffered(double f, char* result) noexcept;
BOOST_JSON_DECL
char* d2s(double f) noexcept;
} // ryu
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,85 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,547 @@
//
// 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
BOOST_JSON_NS_BEGIN
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 & 0x7F);
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 & 0x7F);
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,99 @@
//
// 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>
BOOST_JSON_NS_BEGIN
namespace detail {
class stack
{
storage_ptr sp_;
std::size_t cap_ = 0;
std::size_t size_ = 0;
char* buf_ = nullptr;
public:
BOOST_JSON_DECL
~stack();
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(
buf_ + 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(
buf_ + size_, &t, n);
size_ += n;
}
template<class T>
void
peek(T& t)
{
auto const n = sizeof(T);
BOOST_ASSERT(size_ >= n);
std::memcpy(&t,
buf_ + size_ - n, n);
}
template<class T>
void
pop(T& t)
{
auto const n = sizeof(T);
BOOST_ASSERT(size_ >= n);
size_ -= n;
std::memcpy(
&t, buf_ + size_, n);
}
};
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,350 @@
//
// 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
BOOST_JSON_NS_BEGIN
namespace detail {
class const_stream
{
friend class local_const_stream;
char const* p_;
char const* end_;
public:
const_stream() = default;
const_stream(
const_stream const&) = 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(
stream const&) = default;
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,357 @@
//
// 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>
BOOST_JSON_NS_BEGIN
class value;
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)
{
std::copy(first, last, data());
}
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();
}
};
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,197 @@
//
// 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 <cstddef>
#include <cstring>
#include <cstdint>
BOOST_JSON_NS_BEGIN
namespace detail {
template<int N>
std::uint32_t
load_little_endian(void const* p)
{
// VFALCO do we need to initialize this to 0?
std::uint32_t v;
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)];
}
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);
std::memcpy(&v, p, 3);
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 & 0x7F);
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,277 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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_;
}
};
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,193 @@
//
// 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_VALUE_FROM_HPP
#define BOOST_JSON_DETAIL_VALUE_FROM_HPP
#include <boost/json/storage_ptr.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/value_traits.hpp>
BOOST_JSON_NS_BEGIN
struct value_from_tag { };
template<class T, class = void>
struct has_value_from;
namespace detail {
// The integral_constant parameter here is an
// rvalue reference to make the standard conversion
// sequence to that parameter better, see
// http://eel.is/c++draft/over.ics.rank#3.2.6
template<std::size_t N, class T>
void
tuple_to_array(
T&&,
array&,
std::integral_constant<std::size_t, N>&&)
{
}
template<std::size_t N, std::size_t I, class T>
void
tuple_to_array(
T&& t,
array& arr,
const std::integral_constant<std::size_t, I>&)
{
using std::get;
arr.emplace_back(value_from(
get<I>(std::forward<T>(t)), arr.storage()));
return detail::tuple_to_array<N>(std::forward<T>(t),
arr, std::integral_constant<std::size_t, I + 1>());
}
//----------------------------------------------------------
// Native conversion
template<class T, typename std::enable_if<
detail::value_constructible<T>::value>::type* = nullptr>
void
tag_invoke(
value_from_tag,
value& jv,
T&& from)
{
jv = std::forward<T>(from);
}
template<class T, typename std::enable_if<
std::is_same<detail::remove_cvref<T>,
std::nullptr_t>::value>::type* = nullptr>
void
tag_invoke(
value_from_tag,
value& jv,
T&&)
{
// do nothing
BOOST_ASSERT(jv.is_null());
(void)jv;
}
//----------------------------------------------------------
// Generic conversions
// string-like types
// NOTE: original check for size used is_convertible but
// MSVC-140 selects wrong specialisation if used
template<class T, typename std::enable_if<
std::is_constructible<remove_cvref<T>, const char*, std::size_t>::value &&
std::is_convertible<decltype(std::declval<T&>().data()), const char*>::value &&
std::is_integral<decltype(std::declval<T&>().size())>::value
>::type* = nullptr>
void
value_from_generic(
value& jv,
T&& from,
priority_tag<3>)
{
jv.emplace_string().assign(
from.data(), from.size());
}
// tuple-like types
template<class T, typename std::enable_if<
(std::tuple_size<remove_cvref<T>>::value > 0)>::type* = nullptr>
void
value_from_generic(
value& jv,
T&& from,
priority_tag<2>)
{
constexpr std::size_t n =
std::tuple_size<remove_cvref<T>>::value;
array& arr = jv.emplace_array();
arr.reserve(n);
detail::tuple_to_array<n>(std::forward<T>(from),
arr, std::integral_constant<std::size_t, 0>());
}
// map-like types
template<class T, typename std::enable_if<
map_traits<T>::has_unique_keys &&
has_value_from<typename map_traits<T>::pair_value_type>::value &&
std::is_convertible<typename map_traits<T>::pair_key_type,
string_view>::value>::type* = nullptr>
void
value_from_generic(
value& jv,
T&& from,
priority_tag<1>)
{
using std::get;
object& obj = jv.emplace_object();
obj.reserve(container_traits<T>::try_size(from));
for (auto&& elem : from)
obj.emplace(get<0>(elem), value_from(
get<1>(elem), obj.storage()));
}
// all other containers
template<class T, typename std::enable_if<
has_value_from<typename container_traits<T>::
value_type>::value>::type* = nullptr>
void
value_from_generic(
value& jv,
T&& from,
priority_tag<0>)
{
array& result = jv.emplace_array();
result.reserve(container_traits<T>::try_size(from));
for (auto&& elem : from)
result.emplace_back(
value_from(elem, result.storage()));
}
template<class T, void_t<typename std::enable_if<
! detail::value_constructible<T>::value && ! std::is_same<
detail::remove_cvref<T>, std::nullptr_t>::value>::type,
decltype(detail::value_from_generic(std::declval<value&>(),
std::declval<T&&>(), priority_tag<3>()))>* = nullptr>
void
tag_invoke(
value_from_tag,
value& jv,
T&& from)
{
detail::value_from_generic(jv,
std::forward<T>(from), priority_tag<3>());
}
//----------------------------------------------------------
// Calls to value_from are forwarded to this function
// so we can use ADL and hide the built-in tag_invoke
// overloads in the detail namespace
template<class T, void_t<
decltype(tag_invoke(std::declval<value_from_tag&>(),
std::declval<value&>(), std::declval<T&&>()))>* = nullptr>
value
value_from_impl(
T&& from,
storage_ptr sp)
{
value jv(std::move(sp));
tag_invoke(value_from_tag(), jv, std::forward<T>(from));
return jv;
}
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,195 @@
//
// 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_VALUE_TO_HPP
#define BOOST_JSON_DETAIL_VALUE_TO_HPP
#include <boost/json/value.hpp>
#include <boost/json/detail/value_traits.hpp>
#include <type_traits>
BOOST_JSON_NS_BEGIN
template<class>
struct value_to_tag { };
template<class, class = void>
struct has_value_to;
template<class T, class U,
typename std::enable_if<
! std::is_reference<T>::value &&
std::is_same<U, value>::value>::type* = nullptr>
T value_to(U const&);
namespace detail {
//----------------------------------------------------------
// Use native conversion
// identity conversion
inline
value
tag_invoke(
value_to_tag<value>,
value const& jv)
{
return jv;
}
// object
inline
object
tag_invoke(
value_to_tag<object>,
value const& jv)
{
return jv.as_object();
}
// array
inline
array
tag_invoke(
value_to_tag<array>,
value const& jv)
{
return jv.as_array();
}
// string
inline
string
tag_invoke(
value_to_tag<string>,
value const& jv)
{
return jv.as_string();
}
// bool
inline
bool
tag_invoke(
value_to_tag<bool>,
value const& jv)
{
return jv.as_bool();
}
// integral and floating point
template<class T, typename std::enable_if<
std::is_arithmetic<T>::value>::type* = nullptr>
T
tag_invoke(
value_to_tag<T>,
value const& jv)
{
return jv.to_number<T>();
}
//----------------------------------------------------------
// Use generic conversion
// string-like types
// NOTE: original check for size used is_convertible but
// MSVC-140 selects wrong specialisation if used
template<class T, typename std::enable_if<
std::is_constructible<T, const char*, std::size_t>::value &&
std::is_convertible<decltype(std::declval<T&>().data()), const char*>::value &&
std::is_integral<decltype(std::declval<T&>().size())>::value
>::type* = nullptr>
T
value_to_generic(
const value& jv,
priority_tag<2>)
{
auto& str = jv.as_string();
return T(str.data(), str.size());
}
// map like containers
template<class T, typename std::enable_if<
has_value_to<typename map_traits<T>::pair_value_type>::value &&
std::is_constructible<typename map_traits<T>::pair_key_type,
string_view>::value>::type* = nullptr>
T
value_to_generic(
const value& jv,
priority_tag<1>)
{
using value_type = typename
container_traits<T>::value_type;
const object& obj = jv.as_object();
T result;
container_traits<T>::try_reserve(
result, obj.size());
for (const auto& val : obj)
result.insert(value_type{typename map_traits<T>::
pair_key_type(val.key()), value_to<typename
map_traits<T>::pair_value_type>(val.value())});
return result;
}
// all other containers
template<class T, typename std::enable_if<
has_value_to<typename container_traits<T>::
value_type>::value>::type* = nullptr>
T
value_to_generic(
const value& jv,
priority_tag<0>)
{
const array& arr = jv.as_array();
T result;
container_traits<T>::try_reserve(
result, arr.size());
for (const auto& val : arr)
result.insert(end(result), value_to<typename
container_traits<T>::value_type>(val));
return result;
}
// Matches containers
template<class T, void_t<typename std::enable_if<
!std::is_constructible<T, const value&>::value &&
!std::is_arithmetic<T>::value>::type, decltype(
value_to_generic<T>(std::declval<const value&>(),
priority_tag<2>()))>* = nullptr>
T
tag_invoke(
value_to_tag<T>,
value const& jv)
{
return value_to_generic<T>(
jv, priority_tag<2>());
}
//----------------------------------------------------------
// Calls to value_to are forwarded to this function
// so we can use ADL and hide the built-in tag_invoke
// overloads in the detail namespace
template<class T, void_t<
decltype(tag_invoke(std::declval<value_to_tag<T>&>(),
std::declval<const value&>()))>* = nullptr>
T
value_to_impl(
value_to_tag<T> tag,
value const& jv)
{
return tag_invoke(tag, jv);
}
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,186 @@
//
// 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_VALUE_TRAITS_HPP
#define BOOST_JSON_DETAIL_VALUE_TRAITS_HPP
#include <boost/json/detail/config.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
BOOST_JSON_NS_BEGIN
namespace detail {
template<std::size_t N>
struct priority_tag
: priority_tag<N - 1> { };
template<>
struct priority_tag<0> { };
using std::begin;
using std::end;
#ifdef __cpp_lib_nonmember_container_access
using std::size;
#endif
template<typename T, typename = void>
struct container_traits
{
static constexpr bool is_container = false;
};
template<typename T>
struct container_traits<T, typename std::enable_if<
std::is_same<decltype(begin(std::declval<T&>())),
decltype(end(std::declval<T&>()))>::value>::type>
{
private:
template<typename U, typename std::enable_if<
std::is_convertible<decltype(std::declval<U&>().size()),
std::size_t>::value>::type* = nullptr>
static
std::size_t
size_impl(
U&& cont,
priority_tag<2>)
{
return cont.size();
}
template<typename U, typename std::enable_if<
std::is_convertible<decltype(size(std::declval<U&>())),
std::size_t>::value>::type* = nullptr>
static
std::size_t
size_impl(
U& cont,
priority_tag<1>)
{
return size(cont);
}
template<typename U, std::size_t N>
static
std::size_t
size_impl(
U(&)[N],
priority_tag<1>)
{
return N;
}
template<typename U>
static
std::size_t
size_impl(U&, priority_tag<0>)
{
return 0;
}
template<typename U>
static
auto
reserve_impl(
U& cont,
std::size_t size,
priority_tag<1>) ->
void_t<decltype(
std::declval<U&>().reserve(0))>
{
cont.reserve(size);
}
template<typename U>
static
void
reserve_impl(
U&,
std::size_t,
priority_tag<0>) { }
public:
static constexpr bool is_container = true;
using value_type = remove_cvref<
decltype(*begin(std::declval<T&>()))>;
template<typename U>
static
std::size_t
try_size(U& cont)
{
return container_traits::size_impl(
cont, priority_tag<2>());
}
template<typename U>
static
void
try_reserve(
U& cont,
std::size_t size)
{
container_traits::reserve_impl(
cont, size, priority_tag<1>());
}
};
template<typename T, typename = void>
struct map_traits
{
static constexpr bool is_map = false;
static constexpr bool has_unique_keys = false;
};
template<typename T>
struct map_traits<T, void_t<typename remove_cvref<T>::key_type,
typename std::enable_if<container_traits<T>::is_container &&
std::tuple_size<typename remove_cvref<T>::
value_type>::value == 2>::type>>
{
private:
template<typename U, typename = void>
struct unique_keys : std::false_type { };
template<typename U>
struct unique_keys<U, typename std::enable_if<
(std::tuple_size<remove_cvref<decltype(std::declval<
remove_cvref<U>&>().emplace(std::declval<typename
remove_cvref<U>::value_type>()))>>::value > 0)>::type>
: std::true_type { };
public:
static constexpr bool is_map = true;
static constexpr bool has_unique_keys = unique_keys<T>::value;
using pair_key_type = typename std::tuple_element<
0, typename remove_cvref<T>::value_type>::type;
using pair_value_type = typename std::tuple_element<
1, typename remove_cvref<T>::value_type>::type;
static constexpr bool key_converts_to_string =
std::is_convertible<pair_key_type, string_view>::value;
};
// does not include std::nullptr_t
template<class T>
using value_constructible = std::integral_constant<bool,
std::is_same<detail::remove_cvref<T>, value>::value ||
std::is_same<detail::remove_cvref<T>, object>::value ||
std::is_same<detail::remove_cvref<T>, array>::value ||
std::is_same<detail::remove_cvref<T>, string>::value ||
std::is_same<detail::remove_cvref<T>, string_view>::value ||
std::is_arithmetic<detail::remove_cvref<T>>::value ||
std::is_same<detail::remove_cvref<T>,
std::initializer_list<value_ref>>::value ||
std::is_same<detail::remove_cvref<T>, value_ref>::value>;
BOOST_STATIC_ASSERT(value_constructible<value>::value);
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,233 @@
//
// 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>
#ifndef BOOST_JSON_STANDALONE
# include <boost/system/error_code.hpp>
# include <boost/system/system_error.hpp>
#else
# include <system_error>
#endif
BOOST_JSON_NS_BEGIN
#ifdef BOOST_JSON_DOCS
/** The type of error code used by the library.
This type alias is set depending
on how the library is configured:
@par Use with Boost
If the macro `BOOST_JSON_STANDALONE` is
not defined, this type will be an alias
for `boost::system::error_code`.
Compiling a program using the library will
require Boost, and a compiler conforming
to C++11 or later.
@par Use without Boost
If the macro `BOOST_JSON_STANDALONE` is
defined, this type will be an alias
for `std::error_code`.
Compiling a program using the library will
require only a compiler conforming to C++17
or later.
@see https://en.cppreference.com/w/cpp/error/error_code
*/
using error_code = __see_below__;
/** The type of error category used by the library.
This type alias is set depending
on how the library is configured:
@par Use with Boost
If the macro `BOOST_JSON_STANDALONE` is
not defined, this type will be an alias
for `boost::system::error_category`.
Compiling a program using the library will
require Boost, and a compiler conforming
to C++11 or later.
@par Use without Boost
If the macro `BOOST_JSON_STANDALONE` is
defined, this type will be an alias
for `std::error_category`.
Compiling a program using the library will
require only a compiler conforming to C++17
or later.
@see https://en.cppreference.com/w/cpp/error/error_category
*/
using error_category = __see_below__;
/** The type of error condition used by the library.
This type alias is set depending
on how the library is configured:
@par Use with Boost
If the macro `BOOST_JSON_STANDALONE` is
not defined, this type will be an alias
for `boost::system::error_condition`.
Compiling a program using the library will
require Boost, and a compiler conforming
to C++11 or later.
@par Use without Boost
If the macro `BOOST_JSON_STANDALONE` is
defined, this type will be an alias
for `std::error_condition`.
Compiling a program using the library will
require only a compiler conforming to C++17
or later.
@see https://en.cppreference.com/w/cpp/error/error_condition
*/
using error_condition = __see_below__;
/** The type of system error thrown by the library.
This type alias is set depending
on how the library is configured:
@par Use with Boost
If the macro `BOOST_JSON_STANDALONE` is
not defined, this type will be an alias
for `boost::system::system_error`.
Compiling a program using the library will
require Boost, and a compiler conforming
to C++11 or later.
@par Use without Boost
If the macro `BOOST_JSON_STANDALONE` is
defined, this type will be an alias
for `std::system_error`.
Compiling a program using the library will
require only a compiler conforming to C++17
or later.
@see https://en.cppreference.com/w/cpp/error/system_error
*/
using system_error = __see_below__;
/// Returns the generic error category used by the library.
error_category const&
generic_category();
#elif ! defined(BOOST_JSON_STANDALONE)
using error_code = boost::system::error_code;
using error_category = boost::system::error_category;
using error_condition = boost::system::error_condition;
using system_error = boost::system::system_error;
using boost::system::generic_category;
#else
using error_code = std::error_code;
using error_category = std::error_category;
using error_condition = std::error_condition;
using system_error = std::system_error;
using std::generic_category;
#endif
/** 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,
/// The parser encountered an exception and must be reset
exception,
//----------------------------------
/// not a number
not_number,
/// number cast is not exact
not_exact,
/// test failure
test_failure,
};
/** Error conditions corresponding to JSON errors
*/
enum class condition
{
/// A parser-related error
parse_error = 1,
/// An error on assignment to or from a JSON value
assign_error
};
BOOST_JSON_NS_END
#include <boost/json/impl/error.hpp>
#endif

View File

@@ -0,0 +1,33 @@
//
// 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_FWD_HPP
#define BOOST_JSON_FWD_HPP
#include <boost/json/detail/config.hpp>
BOOST_JSON_NS_BEGIN
// Forward declarations for value types
#ifndef BOOST_JSON_DOCS
class array;
class object;
class string;
class value;
class key_value_pair;
class storage_ptr;
#endif
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,554 @@
//
// 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>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
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)
{
if(pos >= t_->size)
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
return (*t_)[pos];
}
value const&
array::
at(std::size_t pos) const
{
if(pos >= t_->size)
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
return (*t_)[pos];
}
value&
array::
operator[](std::size_t pos) noexcept
{
BOOST_ASSERT(pos < t_->size);
return (*t_)[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 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 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);
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();
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,757 @@
//
// 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/json/array.hpp>
#include <boost/json/pilfer.hpp>
#include <boost/json/detail/except.hpp>
#include <cstdlib>
#include <limits>
#include <new>
#include <utility>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
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())
detail::throw_length_error(
"array too large",
BOOST_CURRENT_LOCATION);
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())
detail::throw_length_error(
"array too large",
BOOST_CURRENT_LOCATION);
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()
{
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());
auto const p = &(*t_)[0] +
(pos - &(*t_)[0]);
destroy(p, p + 1);
relocate(p, p + 1, 1);
--t_->size;
return p;
}
auto
array::
erase(
const_iterator first,
const_iterator last) noexcept ->
iterator
{
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)
{
BOOST_ASSERT(this != &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())
detail::throw_length_error(
"array too large",
BOOST_CURRENT_LOCATION);
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;
}
BOOST_JSON_NS_END
#endif

View File

@@ -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_ERROR_HPP
#define BOOST_JSON_IMPL_ERROR_HPP
#include <type_traits>
#ifndef BOOST_JSON_STANDALONE
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
#else
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
#endif
BOOST_JSON_NS_BEGIN
BOOST_JSON_DECL
error_code
make_error_code(error e);
BOOST_JSON_DECL
error_condition
make_error_condition(condition c);
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,123 @@
//
// 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>
BOOST_JSON_NS_BEGIN
error_code
make_error_code(error e)
{
struct codes : error_category
{
const char*
name() const noexcept override
{
return "boost.json";
}
std::string
message(int ev) const override
{
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::exception: return "got exception";
case error::not_number: return "not a number";
case error::not_exact: return "not exact";
case error::test_failure: return "test failure";
}
}
error_condition
default_error_condition(
int ev) const noexcept override
{
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::exception:
return condition::parse_error;
case error::not_number:
case error::not_exact:
return condition::assign_error;
}
}
};
static codes const cat{};
return error_code{static_cast<
std::underlying_type<error>::type>(e), cat};
}
error_condition
make_error_condition(condition c)
{
struct codes : error_category
{
const char*
name() const noexcept override
{
return "boost.json";
}
std::string
message(int cv) const override
{
switch(static_cast<condition>(cv))
{
default:
case condition::parse_error:
return "A JSON parse error occurred";
case condition::assign_error:
return "An error occurred during assignment";
}
}
};
static codes const cat{};
return error_condition{static_cast<
std::underlying_type<condition>::type>(c), cat};
}
BOOST_JSON_NS_END
#endif

View File

@@ -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_IMPL_KIND_IPP
#define BOOST_JSON_IMPL_KIND_IPP
#include <boost/json/kind.hpp>
#include <ostream>
BOOST_JSON_NS_BEGIN
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;
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,171 @@
//
// 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/align.hpp>
#include <boost/json/detail/except.hpp>
#include <memory>
BOOST_JSON_NS_BEGIN
struct alignas(detail::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 = detail::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 = detail::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;
}
BOOST_JSON_NS_END
#endif

View File

@@ -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_IMPL_NULL_RESOURCE_IPP
#define BOOST_JSON_IMPL_NULL_RESOURCE_IPP
#include <boost/json/null_resource.hpp>
#include <boost/json/detail/except.hpp>
BOOST_JSON_NS_BEGIN
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;
/** Destructor
This destroys the resource.
@par Complexity
Constant.
@part Exception Safety
No-throw guarantee.
*/
~null_resource() noexcept = default;
/** 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
{
detail::throw_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;
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,530 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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_;
std::size_t size_;
BOOST_JSON_DECL
void
destroy() noexcept;
public:
explicit
revert_insert(
object& obj) noexcept
: obj_(&obj)
, size_(obj_->size())
{
}
~revert_insert()
{
if(! obj_)
return;
destroy();
obj_->t_->size = static_cast<
index_t>(size_);
}
void
commit() noexcept
{
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;
}
//----------------------------------------------------------
//
// Lookup
//
//----------------------------------------------------------
auto
object::
at(string_view key) ->
value&
{
auto it = find(key);
if(it == end())
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
return it->value();
}
auto
object::
at(string_view key) const ->
value const&
{
auto it = find(key);
if(it == end())
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
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 insert_impl(pilfer(v));
}
template<class M>
auto
object::
insert_or_assign(
string_view key, M&& m) ->
std::pair<iterator, bool>
{
reserve(size() + 1);
auto const result = find_impl(key);
if(result.first)
{
value(std::forward<M>(m),
sp_).swap(result.first->value());
return { result.first, false };
}
key_value_pair kv(key,
std::forward<M>(m), sp_);
return { insert_impl(pilfer(kv),
result.second), true };
}
template<class Arg>
auto
object::
emplace(
string_view key,
Arg&& arg) ->
std::pair<iterator, bool>
{
reserve(size() + 1);
auto const result = find_impl(key);
if(result.first)
return { result.first, false };
key_value_pair kv(key,
std::forward<Arg>(arg), sp_);
return { insert_impl(pilfer(kv),
result.second), true };
}
//----------------------------------------------------------
//
// (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)
detail::throw_length_error(
"object too large",
BOOST_CURRENT_LOCATION);
reserve(n0 + n);
revert_insert r(*this);
while(first != last)
{
insert(*first);
++first;
}
r.commit();
}
//----------------------------------------------------------
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
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,825 @@
//
// 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/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>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
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.data(), key.size(), 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 = find_impl(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()
{
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)
detail::throw_length_error(
"object too large",
BOOST_CURRENT_LOCATION);
reserve(n0 + init.size());
revert_insert r(*this);
if(t_->is_small())
{
for(auto& iv : init)
{
auto result =
find_impl(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
{
auto p = begin() + (pos - begin());
if(t_->is_small())
{
p->~value_type();
--t_->size;
auto const pb = end();
if(p != end())
{
// the casts silence warnings
std::memcpy(
static_cast<void*>(p),
static_cast<void const*>(pb),
sizeof(*p));
}
return p;
}
remove(t_->bucket(p->key()), *p);
p->~value_type();
--t_->size;
auto const pb = end();
if(p != end())
{
auto& head = t_->bucket(pb->key());
remove(head, *pb);
// the casts silence warnings
std::memcpy(
static_cast<void*>(p),
static_cast<void const*>(pb),
sizeof(*p));
access::next(*p) = head;
head = static_cast<
index_t>(p - begin());
}
return p;
}
auto
object::
erase(string_view key) noexcept ->
std::size_t
{
auto it = find(key);
if(it == end())
return 0;
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 =
find_impl(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 =
find_impl(key).first;
if(p)
return p;
return end();
}
bool
object::
contains(
string_view key) const noexcept
{
if(empty())
return false;
return find_impl(
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)
//
//----------------------------------------------------------
auto
object::
find_impl(
string_view key) const noexcept ->
std::pair<
key_value_pair*,
std::size_t>
{
BOOST_ASSERT(t_->capacity > 0);
if(t_->is_small())
{
auto it = &(*t_)[0];
auto const last =
&(*t_)[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;
result.second = t_->digest(key);
auto i = t_->bucket(
result.second);
while(i != null_index_)
{
auto& v = (*t_)[i];
if(v.key() == key)
{
result.first = &v;
return result;
}
i = access::next(v);
}
result.first = nullptr;
return result;
}
auto
object::
insert_impl(
pilfered<key_value_pair> p) ->
std::pair<iterator, bool>
{
// caller is responsible
// for preventing aliasing.
reserve(size() + 1);
auto const result =
find_impl(p.get().key());
if(result.first)
return { result.first, false };
return { insert_impl(
p, result.second), true };
}
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;
}
// rehash to at least `n` buckets
void
object::
rehash(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;
table::deallocate(t_, sp_);
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;
}
}
}
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())
detail::throw_length_error(
"object too large",
BOOST_CURRENT_LOCATION);
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();
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,54 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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,
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,
BOOST_CURRENT_LOCATION);
return jv;
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,136 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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)
{
error_code ec;
auto const n = write_some(
data, size, ec);
if(ec)
detail::throw_system_error(ec,
BOOST_CURRENT_LOCATION);
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)
{
ec = error::extra_data;
p_.fail(ec);
}
return n;
}
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,
BOOST_CURRENT_LOCATION);
return n;
}
value
parser::
release()
{
if( ! p_.done())
{
// prevent undefined behavior
if(! p_.last_error())
p_.fail(error::incomplete);
detail::throw_system_error(
p_.last_error(),
BOOST_CURRENT_LOCATION);
}
return p_.handler().st.release();
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,191 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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());
for(;;)
{
sv = sr.read(
&s[0] + len,
s.size() - len);
len += sv.size();
if(sr.done())
break;
s.resize(
s.capacity() + 1);
}
s.resize(len);
}
std::string
serialize(
value const& jv)
{
std::string s;
serializer sr;
sr.reset(&jv);
serialize_impl(s, sr);
return s;
}
std::string
serialize(
array const& arr)
{
std::string s;
serializer sr;
sr.reset(&arr);
serialize_impl(s, sr);
return s;
}
std::string
serialize(
object const& obj)
{
std::string s;
serializer sr;
sr.reset(&obj);
serialize_impl(s, sr);
return s;
}
std::string
serialize(
string const& str)
{
std::string s;
serializer sr;
sr.reset(&str);
serialize_impl(s, sr);
return s;
}
// this is here for key_value_pair::key()
std::string
serialize(
string_view sv)
{
std::string s;
serializer sr;
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;
// 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;
sr.reset(&arr);
to_ostream(os, sr);
return os;
}
std::ostream&
operator<<(
std::ostream& os,
object const& obj)
{
serializer sr;
sr.reset(&obj);
to_ostream(os, sr);
return os;
}
std::ostream&
operator<<(
std::ostream& os,
string const& str)
{
serializer sr;
sr.reset(&str);
to_ostream(os, sr);
return os;
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,822 @@
//
// 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
BOOST_JSON_NS_BEGIN
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() noexcept = default;
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()));
return true;
}
cs0_ = { buf_, detail::format_double(
buf_, jv_->get_double()) };
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() noexcept
{
// 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);
}
BOOST_JSON_NS_END
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif

View File

@@ -0,0 +1,78 @@
//
// 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/json/detail/align.hpp>
#include <boost/json/detail/except.hpp>
#include <memory>
BOOST_JSON_NS_BEGIN
static_resource::
~static_resource() noexcept = default;
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 = detail::align(
align, n, p_, n_);
if(! p)
detail::throw_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;
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,148 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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)
{
error_code ec;
auto const n = write_some(
data, size, ec);
if(ec)
detail::throw_system_error(ec,
BOOST_CURRENT_LOCATION);
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)
{
ec = error::extra_data;
p_.fail(ec);
}
return n;
}
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,
BOOST_CURRENT_LOCATION);
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,
BOOST_CURRENT_LOCATION);
}
value
stream_parser::
release()
{
if(! p_.done())
{
// prevent undefined behavior
finish();
}
return p_.handler().st.release();
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,236 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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);
std::copy(first, last,
impl_.append(n, sp_));
}
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());
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,416 @@
//
// 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>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
//
// 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(*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())
detail::throw_out_of_range(
BOOST_CURRENT_LOCATION);
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)
{
BOOST_ASSERT(this != &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;
}
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,497 @@
//
// 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/json/value.hpp>
#include <cstring>
#include <limits>
#include <new>
#include <utility>
BOOST_JSON_NS_BEGIN
value::
~value()
{
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
::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));
}
//----------------------------------------------------------
//
// 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;
}
//----------------------------------------------------------
BOOST_JSON_NS_END
#endif

View File

@@ -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
#include <boost/json/value_from.hpp>
BOOST_JSON_NS_BEGIN
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_from(
*reinterpret_cast<
T const*>(p),
std::move(sp));
}
template<class T>
value
value_ref::
from_rvalue(
void* p,
storage_ptr sp)
{
return value_from(
std::move(
*reinterpret_cast<T*>(p)),
std::move(sp));
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,187 @@
//
// 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>
BOOST_JSON_NS_BEGIN
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;
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,472 @@
//
// 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>
BOOST_JSON_NS_BEGIN
//--------------------------------------
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)));
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 + (top_ - begin_);
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)));
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 + (top_ - begin_);
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_);
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,59 @@
//
// 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
BOOST_JSON_NS_BEGIN
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());
}
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,163 @@
//
// 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>
BOOST_JSON_NS_BEGIN
/** 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);
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,178 @@
//
// 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>
#ifdef BOOST_JSON_STANDALONE
# if __has_include(<memory_resource>)
# include <memory_resource>
# ifndef __cpp_lib_memory_resource
# error Support for std::memory_resource is required to use Boost.JSON standalone
# endif
# elif __has_include(<experimental/memory_resource>)
# include <experimental/memory_resource>
# warning Support for std::memory_resource is required to use Boost.JSON standalone, using std::experimental::memory_resource as fallback
# else
# error Header <memory_resource> is required to use Boost.JSON standalone
# endif
#else
# include <boost/container/pmr/memory_resource.hpp>
# include <boost/container/pmr/polymorphic_allocator.hpp>
#endif
BOOST_JSON_NS_BEGIN
#ifdef BOOST_JSON_DOCS
/** The type of memory resource used by the library.
This type alias is set depending
on how the library is configured:
@par Use with Boost
If the macro `BOOST_JSON_STANDALONE` is
not defined, this type will be an alias
for `boost::container::pmr::memory_resource`.
Compiling a program using the library will
require Boost, and a compiler conforming
to C++11 or later.
@par Use without Boost
If the macro `BOOST_JSON_STANDALONE` is
defined, this type will be an alias
for `std::pmr::memory_resource`.
Compiling a program using the library will
require only a compiler conforming to C++17
or later.
@see https://en.cppreference.com/w/cpp/memory/memory_resource
*/
class memory_resource
{
};
/** The type of polymorphic allocator used by the library.
This type alias is set depending
on how the library is configured:
@par Use with Boost
If the macro `BOOST_JSON_STANDALONE` is
not defined, this type will be an alias template
for `boost::container::pmr::polymorphic_allocator`.
Compiling a program using the library will
require Boost, and a compiler conforming
to C++11 or later.
@par Use without Boost
If the macro `BOOST_JSON_STANDALONE` is
defined, this type will be an alias template
for `std::pmr::polymorphic_allocator`.
Compiling a program using the library will
require only a compiler conforming to C++17
or later.
@see https://en.cppreference.com/w/cpp/memory/polymorphic_allocator
*/
template<class T>
class polymorphic_allocator;
// VFALCO Bug: doc toolchain won't make this a ref
//using memory_resource = __see_below__;
#elif defined(BOOST_JSON_STANDALONE)
# if __has_include(<memory_resource>)
using memory_resource = std::pmr::memory_resource;
template<class T>
using polymorphic_allocator =
std::pmr::polymorphic_allocator<T>;
# else
using memory_resource = std::experimental::pmr::memory_resource;
template<class T>
using polymorphic_allocator =
std::experimental::pmr::polymorphic_allocator<T>;
# endif
#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;
};
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,350 @@
//
// 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>
BOOST_JSON_NS_BEGIN
#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 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_CLASS_DECL
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;
};
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,35 @@
//
// 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>
BOOST_JSON_NS_BEGIN
/** 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;
BOOST_JSON_NS_END
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,106 @@
//
// 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>
BOOST_JSON_NS_BEGIN
/** 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.
*/
BOOST_JSON_DECL
value
parse(
string_view s,
error_code& ec,
storage_ptr sp = {},
parse_options const& opt = {});
/** Parse a string of JSON into 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.
*/
BOOST_JSON_DECL
value
parse(
string_view s,
storage_ptr sp = {},
parse_options const& opt = {});
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,83 @@
//
// 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>
BOOST_JSON_NS_BEGIN
/** 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. 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;
/** 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;
};
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,787 @@
//
// 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>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
/** A DOM parser for JSON contained in a single buffer.
This class is used to parse a JSON 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. 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
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, 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 JSONs 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
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 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 JSONs 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.
This function is used to reset the parser to
prepare it for parsing a new complete JSON.
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.
This function parses a complete JSON contained
in the specified character buffer. Additional
characters past the end of the complete JSON
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 JSONs
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
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.
@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);
/** Parse a buffer containing a complete JSON.
This function parses a complete JSON contained
in the specified character buffer. Additional
characters past the end of the complete JSON
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 JSONs
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
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.
@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.
This function parses a complete JSON contained
in the specified character buffer. Additional
characters past the end of the complete JSON
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 JSONs
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
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.
@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);
}
/** Parse a buffer containing a complete JSON.
This function parses a complete JSON contained
in the specified character buffer. Additional
characters past the end of the complete JSON
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 JSONs
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
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.
@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.
This function parses a complete JSON contained
in the specified character buffer. The entire
buffer must be consumed; if there are additional
characters past the end of the complete JSON,
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
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.
@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);
/** Parse a buffer containing a complete JSON.
This function parses a complete JSON contained
in the specified character buffer. The entire
buffer must be consumed; if there are additional
characters past the end of the complete JSON,
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
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.
@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.
This function parses a complete JSON contained
in the specified character buffer. The entire
buffer must be consumed; if there are additional
characters past the end of the complete JSON,
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
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.
@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);
}
/** Parse a buffer containing a complete JSON.
This function parses a complete JSON contained
in the specified character buffer. The entire
buffer must be consumed; if there are additional
characters past the end of the complete JSON,
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
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.
@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 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.
@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();
};
BOOST_JSON_NS_END
#endif

View File

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

View File

@@ -0,0 +1,104 @@
//
// 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_SERIALIZE_HPP
#define BOOST_JSON_SERIALIZE_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/value.hpp>
#include <iosfwd>
#include <string>
BOOST_JSON_NS_BEGIN
/** Return a string representing a serialized element.
This function serializes `t` as JSON and returns
it as a `std::string`.
@par Complexity
Constant or linear in the size of `t`.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return The serialized string
@param t The value to serialize
*/
/** @{ */
BOOST_JSON_DECL
std::string
serialize(value const& t);
BOOST_JSON_DECL
std::string
serialize(array const& t);
BOOST_JSON_DECL
std::string
serialize(object const& t);
BOOST_JSON_DECL
std::string
serialize(string const& t);
BOOST_JSON_DECL
std::string
serialize(string_view t);
/** @} */
/** Serialize an element to an output stream.
This function serializes the specified element
as JSON into the output stream.
@return `os`.
@par Complexity
Constant or linear in the size of `t`.
@par Exception Safety
Strong guarantee.
Calls to `memory_resource::allocate` may throw.
@param os The output stream to serialize to.
@param t The value to serialize
*/
/** @{ */
BOOST_JSON_DECL
std::ostream&
operator<<(
std::ostream& os,
value const& t);
BOOST_JSON_DECL
std::ostream&
operator<<(
std::ostream& os,
array const& t);
BOOST_JSON_DECL
std::ostream&
operator<<(
std::ostream& os,
object const& t);
BOOST_JSON_DECL
std::ostream&
operator<<(
std::ostream& os,
string const& t);
/** @} */
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,286 @@
//
// 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_SERIALIZER_HPP
#define BOOST_JSON_SERIALIZER_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/format.hpp>
#include <boost/json/detail/stack.hpp>
#include <boost/json/detail/stream.hpp>
BOOST_JSON_NS_BEGIN
/** A serializer for JSON.
This class traverses an instance of a library
type and emits serialized JSON text by filling
in one or more caller-provided buffers. To use,
declare a variable and call @ref reset with
a pointer to the variable you want to serialize.
Then call @ref read over and over until
@ref done returns `true`.
@par Example
This demonstrates how the serializer may
be used to print a JSON value to an output
stream.
@code
void print( std::ostream& os, value const& jv)
{
serializer sr;
sr.reset( &jv );
while( ! sr.done() )
{
char buf[ 4000 ];
os << sr.read( buf );
}
}
@endcode
@par Thread Safety
The same instance may not be accessed concurrently.
*/
class serializer
{
enum class state : char;
// VFALCO Too many streams
using stream = detail::stream;
using const_stream = detail::const_stream;
using local_stream = detail::local_stream;
using local_const_stream =
detail::local_const_stream;
using fn_t = bool (serializer::*)(stream&);
#ifndef BOOST_JSON_DOCS
union
{
value const* pv_;
array const* pa_;
object const* po_;
};
#endif
fn_t fn0_ = &serializer::write_null<true>;
fn_t fn1_ = &serializer::write_null<false>;
value const* jv_ = nullptr;
detail::stack st_;
const_stream cs0_;
char buf_[detail::max_number_chars + 1];
bool done_ = false;
inline bool suspend(state st);
inline bool suspend(
state st, array::const_iterator it, array const* pa);
inline bool suspend(
state st, object::const_iterator it, object const* po);
template<bool StackEmpty> bool write_null (stream& ss);
template<bool StackEmpty> bool write_true (stream& ss);
template<bool StackEmpty> bool write_false (stream& ss);
template<bool StackEmpty> bool write_string (stream& ss);
template<bool StackEmpty> bool write_number (stream& ss);
template<bool StackEmpty> bool write_array (stream& ss);
template<bool StackEmpty> bool write_object (stream& ss);
template<bool StackEmpty> bool write_value (stream& ss);
inline string_view read_some(char* dest, std::size_t size);
public:
/// Move constructor (deleted)
serializer(serializer&&) = delete;
/** Destructor
All temporary storage is deallocated.
@par Complexity
Constant
@par Exception Safety
No-throw guarantee.
*/
BOOST_JSON_DECL
~serializer() noexcept;
/** Default constructor
This constructs a serializer with no value.
The value may be set later by calling @ref reset.
If serialization is attempted with no value,
the output is as if a null value is serialized.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
BOOST_JSON_DECL
serializer() noexcept;
/** Returns `true` if the serialization is complete
This function returns `true` when all of the
characters in the serialized representation of
the value have been read.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
bool
done() const noexcept
{
return done_;
}
/** Reset the serializer for a new element
This function prepares the serializer to emit
a new serialized JSON representing `*p`.
Any internally allocated memory is
preserved and re-used for the new output.
@param p A pointer to the element to serialize.
Ownership is not transferred; The caller is
responsible for ensuring that the lifetime of
`*p` extends until it is no longer needed.
*/
/** @{ */
BOOST_JSON_DECL
void
reset(value const* p) noexcept;
BOOST_JSON_DECL
void
reset(array const* p) noexcept;
BOOST_JSON_DECL
void
reset(object const* p) noexcept;
BOOST_JSON_DECL
void
reset(string const* p) noexcept;
/** @} */
/** Reset the serializer for a new string
This function prepares the serializer to emit
a new serialized JSON representing the string.
Any internally allocated memory is
preserved and re-used for the new output.
@param sv The characters representing the string.
Ownership is not transferred; The caller is
responsible for ensuring that the lifetime of
the characters reference by `sv` extends
until it is no longer needed.
*/
BOOST_JSON_DECL
void
reset(string_view sv) noexcept;
/** Read the next buffer of serialized JSON
This function attempts to fill the caller
provided buffer starting at `dest` with
up to `size` characters of the serialized
JSON that represents the value. If the
buffer is not large enough, multiple calls
may be required.
\n
If serialization completes during this call;
that is, that all of the characters belonging
to the serialized value have been written to
caller-provided buffers, the function
@ref done will return `true`.
@par Preconditions
`this->done() == true`
@par Complexity
Linear in `size`.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@return A @ref string_view containing the
characters written, which may be less than
`size`.
@param dest A pointer to valid memory of at
least `size` bytes.
@param size The maximum number of characters
to write to the memory pointed to by `dest`.
*/
BOOST_JSON_DECL
string_view
read(char* dest, std::size_t size);
/** Read the next buffer of serialized JSON
This function allows reading into a
character array, with a deduced maximum size.
@par Preconditions
`this->done() == true`
@par Effects
@code
return this->read( dest, N );
@endcode
@par Complexity
Linear in `N`.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@return A @ref string_view containing the
characters written, which may be less than
`size`.
@param dest The character array to write to.
*/
template<std::size_t N>
string_view
read(char(&dest)[N])
{
return read(dest, N);
}
#ifndef BOOST_JSON_DOCS
// Safety net for accidental buffer overflows
template<std::size_t N>
string_view
read(char(&dest)[N], std::size_t n)
{
// If this goes off, check your parameters
// closely, chances are you passed an array
// thinking it was a pointer.
BOOST_ASSERT(n <= N);
return read(dest, n);
}
#endif
};
BOOST_JSON_NS_END
#endif

View File

@@ -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_SRC_HPP
#define BOOST_JSON_SRC_HPP
/*
This file is meant to be included once,
in a translation unit of the program.
*/
#ifndef BOOST_JSON_SOURCE
#define BOOST_JSON_SOURCE
#endif
// We include this in case someone is using
// src.hpp as their main JSON header file
// https://github.com/boostorg/json/issues/223#issuecomment-689264149
#include <boost/json.hpp>
#include <boost/json/detail/config.hpp>
#include <boost/json/impl/array.ipp>
#include <boost/json/impl/error.ipp>
#include <boost/json/impl/kind.ipp>
#include <boost/json/impl/monotonic_resource.ipp>
#include <boost/json/impl/null_resource.ipp>
#include <boost/json/impl/object.ipp>
#include <boost/json/impl/parse.ipp>
#include <boost/json/impl/parser.ipp>
#include <boost/json/impl/serialize.ipp>
#include <boost/json/impl/serializer.ipp>
#include <boost/json/impl/static_resource.ipp>
#include <boost/json/impl/stream_parser.ipp>
#include <boost/json/impl/string.ipp>
#include <boost/json/impl/value.ipp>
#include <boost/json/impl/value_stack.ipp>
#include <boost/json/impl/value_ref.ipp>
#include <boost/json/detail/impl/shared_resource.ipp>
#include <boost/json/detail/impl/default_resource.ipp>
#include <boost/json/detail/impl/except.ipp>
#include <boost/json/detail/impl/format.ipp>
#include <boost/json/detail/impl/handler.ipp>
#include <boost/json/detail/impl/stack.ipp>
#include <boost/json/detail/impl/string_impl.ipp>
#include <boost/json/detail/ryu/impl/d2s.ipp>
#endif

View File

@@ -0,0 +1,243 @@
//
// 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_STATIC_RESOURCE_HPP
#define BOOST_JSON_STATIC_RESOURCE_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/memory_resource.hpp>
#include <cstddef>
BOOST_JSON_NS_BEGIN
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4275) // non dll-interface class used as base for dll-interface class
#endif
//----------------------------------------------------------
/** A resource using a caller-owned buffer, 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 is constructed from a caller-owned buffer
from which subsequent calls to allocate are apportioned.
When a memory request cannot be satisfied from the
free bytes remaining in the buffer, the allocation
request fails with the exception `std::bad_alloc`.
\n
@par Example
This parses a JSON into a value which uses a local
stack buffer, then prints the result.
@code
unsigned char buf[ 4000 ];
static_resource mr( buf );
// Parse the string, using our memory resource
value const jv = parse( "[1,2,3]", &mr );
// Print the JSON
std::cout << jv;
@endcode
@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_CLASS_DECL
static_resource final
: public memory_resource
{
void* p_;
std::size_t n_;
std::size_t size_;
public:
/// Copy constructor (deleted)
static_resource(
static_resource const&) = delete;
/// Copy assignment (deleted)
static_resource& operator=(
static_resource const&) = delete;
/** Destructor
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
~static_resource() noexcept;
/** Constructor
This constructs the resource to use the specified
buffer for subsequent calls to allocate. When the
buffer is exhausted, allocate will throw
`std::bad_alloc`.
@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`.
*/
/** @{ */
static_resource(
unsigned char* buffer,
std::size_t size) noexcept;
#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
static_resource(
std::byte* buffer,
std::size_t size) noexcept
: static_resource(reinterpret_cast<
unsigned char*>(buffer), size)
{
}
#endif
/** @} */
/** Constructor
This constructs the resource to use the specified
buffer for subsequent calls to allocate. When the
buffer is exhausted, allocate will throw
`std::bad_alloc`.
@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.
*/
/** @{ */
template<std::size_t N>
explicit
static_resource(
unsigned char(&buffer)[N]) noexcept
: static_resource(&buffer[0], N)
{
}
#if defined(__cpp_lib_byte) || defined(BOOST_JSON_DOCS)
template<std::size_t N>
explicit
static_resource(
std::byte(&buffer)[N]) noexcept
: static_resource(&buffer[0], N)
{
}
#endif
/** @} */
#ifndef BOOST_JSON_DOCS
// Safety net for accidental buffer overflows
template<std::size_t N>
static_resource(
unsigned char(&buffer)[N], std::size_t n) noexcept
: static_resource(&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>
static_resource(
std::byte(&buffer)[N], std::size_t n) noexcept
: static_resource(&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
/** Release all allocated memory.
This function resets the buffer provided upon
construction so that all of the valid bytes are
available for subsequent allocation.
@par Complexity
Constant
@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<
static_resource>
{
static constexpr bool value = true;
};
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,529 @@
//
// 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_STORAGE_PTR_HPP
#define BOOST_JSON_STORAGE_PTR_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/memory_resource.hpp>
#include <boost/json/detail/shared_resource.hpp>
#include <boost/json/detail/default_resource.hpp>
#include <cstddef>
#include <new>
#include <type_traits>
#include <utility>
BOOST_JSON_NS_BEGIN
/** A smart pointer to a @ref memory_resource
This container is used to hold a pointer to a
memory resource. The pointed-to resource is
always valid; default-constructed pointers
use the default memory resource, which calls
into the standard global system heap.
Depending on the means of construction, the
ownership will be either:
@li Non-owning, when constructing from a raw
pointer to @ref memory_resource or from a
@ref polymorphic_allocator. In this case the
caller is responsible for ensuring that the
lifetime of the memory resource extends until
there are no more calls to allocate or
deallocate.
@li Owning, when constructing using the function
@ref make_shared_resource. In this case
ownership is shared; the lifetime of the memory
resource extends until the last copy of the
@ref storage_ptr is destroyed.
@par Examples
These statements create a memory resource on the
stack and construct a pointer from it without
taking ownership:
@code
monotonic_resource mr; // Create our memory resource on the stack
storage_ptr sp( &mr ); // Construct a non-owning pointer to the resource
@endcode
This function creates a pointer to a memory
resource using shared ownership and returns it.
The lifetime of the memory resource extends until
the last copy of the pointer is destroyed:
@code
// Create a counted memory resource and return it
storage_ptr make_storage()
{
return make_shared_resource< monotonic_resource >();
}
@endcode
@par Thread Safety
Instances of this type provide the default level of
thread safety for all C++ objects. Specifically, it
conforms to
<a href="http://eel.is/c++draft/res.on.data.races">
16.4.6.10 Data race avoidance</a>.
@see
@ref make_shared_resource,
@ref memory_resource,
@ref polymorphic_allocator
*/
class storage_ptr
{
#ifndef BOOST_JSON_DOCS
// VFALCO doc toolchain shows this when it shouldn't
friend struct detail::shared_resource;
#endif
using shared_resource =
detail::shared_resource;
using default_resource =
detail::default_resource;
std::uintptr_t i_;
shared_resource*
get_shared() const noexcept
{
return static_cast<shared_resource*>(
reinterpret_cast<memory_resource*>(
i_ & ~3));
}
void
addref() const noexcept
{
if(is_shared())
get_shared()->refs.fetch_add(
1, std::memory_order_relaxed);
}
void
release() const noexcept
{
if(is_shared())
{
auto const p = get_shared();
if(p->refs.fetch_sub(1,
std::memory_order_acq_rel) == 1)
delete p;
}
}
template<class T>
storage_ptr(
detail::shared_resource_impl<T>* p) noexcept
: i_(reinterpret_cast<std::uintptr_t>(
static_cast<memory_resource*>(p)) + 1 +
(json::is_deallocate_trivial<T>::value ? 2 : 0))
{
BOOST_ASSERT(p);
}
public:
/** Destructor
If the pointer has shared ownership of the
resource, the shared ownership is released.
If this is the last owned copy, the memory
resource is destroyed.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
~storage_ptr()
{
release();
}
/** Constructor
This constructs a non-owning pointer that refers
to the default memory resource, which uses the
standard global system heap to allocate and
free memory.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
storage_ptr() noexcept
: i_(0)
{
}
/** Constructor
This constructs a non-owning pointer that
points to the memory resource `r`.
The caller is responsible for maintaining the
lifetime of the pointed-to @ref memory_resource.
@par Constraints
@code
std::is_convertible< T*, memory_resource* >::value == true
@endcode
@par Preconditions
@code
r != nullptr
@endcode
@par Exception Safety
No-throw guarantee.
@param r A pointer to the memory resource to use.
This may not be null.
*/
template<class T
#ifndef BOOST_JSON_DOCS
, class = typename std::enable_if<
std::is_convertible<T*,
memory_resource*>::value>::type
#endif
>
storage_ptr(T* r) noexcept
: i_(reinterpret_cast<std::uintptr_t>(
static_cast<memory_resource *>(r)) +
(json::is_deallocate_trivial<T>::value ? 2 : 0))
{
BOOST_ASSERT(r);
}
/** Constructor
This constructs a non-owning pointer that
points to the same memory resource as `alloc`,
obtained by calling `alloc.resource()`.
The caller is responsible for maintaining the
lifetime of the pointed-to @ref memory_resource.
@par Constraints
@code
std::is_convertible< T*, memory_resource* >::value == true
@endcode
@par Exception Safety
No-throw guarantee.
@param alloc A @ref polymorphic_allocator to
construct from.
*/
template<class T>
storage_ptr(
polymorphic_allocator<T> const& alloc) noexcept
: i_(reinterpret_cast<std::uintptr_t>(
alloc.resource()))
{
}
/** Move constructor
This function constructs a pointer that
points to the same memory resource as `other`,
with the same ownership:
@li If `other` is non-owning, then `*this`
will be be non-owning.
@li If `other` has shared ownership, then
ownership will be transferred to `*this`.
After construction, `other` will point
to the default memory resource.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
@param other The pointer to construct from.
*/
storage_ptr(
storage_ptr&& other) noexcept
: i_(detail::exchange(other.i_, 0))
{
}
/** Copy constructor
This function constructs a pointer that
points to the same memory resource as `other`,
with the same ownership:
@li If `other` is non-owning, then `*this`
will be be non-owning.
@li If `other` has shared ownership, then
`*this` will acquire shared ownership.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
@param other The pointer to construct from.
*/
storage_ptr(
storage_ptr const& other) noexcept
: i_(other.i_)
{
addref();
}
/** Move assignment
This function assigns a pointer that
points to the same memory resource as `other`,
with the same ownership:
@li If `other` is non-owning, then `*this`
will be be non-owning.
@li If `other` has shared ownership, then
ownership will be transferred to `*this`.
After assignment, `other` will point
to the default memory resource.
If `*this` previously had shared ownership,
it is released before the function returns.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
@param other The storage pointer to move.
*/
storage_ptr&
operator=(
storage_ptr&& other) noexcept
{
release();
i_ = detail::exchange(other.i_, 0);
return *this;
}
/** Copy assignment.
This function assigns a pointer that
points to the same memory resource as `other`,
with the same ownership:
@li If `other` is non-owning, then `*this`
will be be non-owning.
@li If `other` has shared ownership, then
`*this` will acquire shared ownership.
If `*this` previously had shared ownership,
it is released before the function returns.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
@param other The storage pointer to copy.
*/
storage_ptr&
operator=(
storage_ptr const& other) noexcept
{
other.addref();
release();
i_ = other.i_;
return *this;
}
/** Return `true` if ownership of the memory resource is shared.
This function returns true for memory resources
created using @ref make_shared_resource.
*/
bool
is_shared() const noexcept
{
return (i_ & 1) != 0;
}
/** Return `true` if calling `deallocate` on the memory resource has no effect.
This function is used to determine if the deallocate
function of the pointed to memory resource is trivial.
The value of @ref is_deallocate_trivial is evaluated
and saved when the memory resource is constructed
and the type is known, before the type is erased.
*/
bool
is_deallocate_trivial() const noexcept
{
return (i_ & 2) != 0;
}
/** Return `true` if ownership of the memory resource is not shared and deallocate is trivial.
This function is used to determine if calls to deallocate
can effectively be skipped.
@par Effects
Returns `! this->is_shared() && this->is_deallocate_trivial()`
*/
bool
is_not_shared_and_deallocate_is_trivial() const noexcept
{
return (i_ & 3) == 2;
}
/** Return a pointer to the memory resource.
This function returns a pointer to the
referenced @ref memory_resource.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
memory_resource*
get() const noexcept
{
if(i_ != 0)
return reinterpret_cast<
memory_resource*>(i_ & ~3);
return default_resource::get();
}
/** Return a pointer to the memory resource.
This function returns a pointer to the
referenced @ref memory_resource.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
memory_resource*
operator->() const noexcept
{
return get();
}
/** Return a reference to the memory resource.
This function returns a reference to the
pointed-to @ref memory_resource.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
memory_resource&
operator*() const noexcept
{
return *get();
}
template<class U, class... Args>
friend
storage_ptr
make_shared_resource(Args&&... args);
};
/** Return shared ownership of a new, dynamically allocated memory resource.
This function dynamically allocates a new memory resource
as if by `operator new` that uses shared ownership. The
lifetime of the memory resource will be extended until
the last @ref storage_ptr which points to it is destroyed.
@par Mandates
@code
std::is_base_of< memory_resource, T >::value == true
@endcode
@par Complexity
Same as `new T( std::forward<Args>(args)... )`.
@par Exception Safety
Strong guarantee.
@tparam T The type of memory resource to create.
@param args Parameters forwarded to the constructor of `T`.
*/
template<class T, class... Args>
storage_ptr
make_shared_resource(Args&&... args)
{
// If this generates an error, it means that
// `T` is not a memory resource.
BOOST_STATIC_ASSERT(
std::is_base_of<
memory_resource, T>::value);
return storage_ptr(new
detail::shared_resource_impl<T>(
std::forward<Args>(args)...));
}
/** Return true if two storage pointers point to the same memory resource.
This function returns `true` if the @ref memory_resource
objects pointed to by `lhs` and `rhs` have the
same address.
*/
inline
bool
operator==(
storage_ptr const& lhs,
storage_ptr const& rhs) noexcept
{
return lhs.get() == rhs.get();
}
/** Return true if two storage pointers point to different memory resources.
This function returns `true` if the @ref memory_resource
objects pointed to by `lhs` and `rhs` have different
addresses.
*/
inline
bool
operator!=(
storage_ptr const& lhs,
storage_ptr const& rhs) noexcept
{
return lhs.get() != rhs.get();
}
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,985 @@
//
// 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_STREAM_PARSER_HPP
#define BOOST_JSON_STREAM_PARSER_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/basic_parser.hpp>
#include <boost/json/parse_options.hpp>
#include <boost/json/storage_ptr.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/handler.hpp>
#include <type_traits>
#include <cstddef>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
/** A DOM parser for JSON contained in multiple buffers.
This class is used to parse a JSON contained in a
series of one or more character buffers, into a
@ref value container. It implements a
<a href="https://en.wikipedia.org/wiki/Streaming_algorithm">
<em>streaming algorithm</em></a>, allowing these
parsing strategies:
@li Parse a JSON file a piece at a time.
@li Parse incoming JSON as it arrives,
one buffer at a time.
@li Parse with bounded resource consumption
per cycle.
@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
one or more times to parse a single, complete JSON.
Call @ref done to determine if the parse has completed.
To indicate there are no more buffers, call @ref finish.
If the parse is successful, call @ref release to take
ownership of the value:
@code
stream_parser p; // construct a parser
p.write( "[1,2" ); // parse some of a JSON
p.write( ",3,4]" ); // parse the rest of the JSON
assert( p.done() ); // we have a complete JSON
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, 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 JSONs or containing
different protocol data:
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write_some( "[1,2" ); // parse some of a JSON
assert( n == 4 ); // all characters consumed
n = p.write_some( ",3,4] null" ); // parse the remainder of the JSON
assert( n == 6 ); // only some characters consumed
assert( p.done() ); // we have a complete JSON
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 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 JSONs 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 parser,
@ref parse_options,
*/
class stream_parser
{
basic_parser<detail::handler> p_;
public:
/// Copy constructor (deleted)
stream_parser(
stream_parser const&) = delete;
/// Copy assignment (deleted)
stream_parser& operator=(
stream_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.
*/
~stream_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
stream_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.
*/
stream_parser() noexcept
: stream_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
stream_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
stream_parser(storage_ptr sp) noexcept
: stream_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>
stream_parser(
storage_ptr sp,
parse_options const& opt,
unsigned char(&buffer)[N]) noexcept
: stream_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`.
*/
stream_parser(
storage_ptr sp,
parse_options const& opt,
std::byte* buffer,
std::size_t size) noexcept
: stream_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>
stream_parser(
storage_ptr sp,
parse_options const& opt,
std::byte(&buffer)[N]) noexcept
: stream_parser(std::move(sp),
opt, &buffer[0], N)
{
}
#endif
#ifndef BOOST_JSON_DOCS
// Safety net for accidental buffer overflows
template<std::size_t N>
stream_parser(
storage_ptr sp,
parse_options const& opt,
unsigned char(&buffer)[N],
std::size_t n) noexcept
: stream_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>
stream_parser(
storage_ptr sp,
parse_options const& opt,
std::byte(&buffer)[N], std::size_t n) noexcept
: stream_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.
This function is used to reset the parser to
prepare it for parsing a new complete JSON.
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;
/** 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 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 p_.done();
}
/** Parse a buffer containing all or part of a complete JSON.
This function parses JSON contained in the
specified character buffer. If parsing completes,
any additional characters past the end of the
complete JSON 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 JSONs or
containing different protocol data.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write_some( "[1,2" ); // parse the first part of the JSON
assert( n == 4 ); // all characters consumed
n = p.write_some( "3,4] null" ); // parse the rest of the JSON
assert( n == 5 ); // only some characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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);
/** Parse a buffer containing all or part of a complete JSON.
This function parses JSON contained in the
specified character buffer. If parsing completes,
any additional characters past the end of the
complete JSON 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 JSONs or
containing different protocol data.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write_some( "[1,2" ); // parse the first part of the JSON
assert( n == 4 ); // all characters consumed
n = p.write_some( "3,4] null" ); // parse the rest of the JSON
assert( n == 5 ); // only some characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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 all or part of a complete JSON.
This function parses JSON contained in the
specified character buffer. If parsing completes,
any additional characters past the end of the
complete JSON 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 JSONs or
containing different protocol data.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write_some( "[1,2" ); // parse the first part of the JSON
assert( n == 4 ); // all characters consumed
n = p.write_some( "3,4] null" ); // parse the rest of the JSON
assert( n == 5 ); // only some characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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);
}
/** Parse a buffer containing all or part of a complete JSON.
This function parses JSON contained in the
specified character buffer. If parsing completes,
any additional characters past the end of the
complete JSON 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 JSONs or
containing different protocol data.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write_some( "[1,2" ); // parse the first part of the JSON
assert( n == 4 ); // all characters consumed
n = p.write_some( "3,4] null" ); // parse the rest of the JSON
assert( n == 5 ); // only some characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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 all or part of a complete JSON.
This function parses a all or part of a JSON
contained in the specified character buffer. The
entire buffer must be consumed; if there are
additional characters past the end of the complete
JSON, the parse fails and an error is returned.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write( "[1,2" ); // parse some of the JSON
assert( n == 4 ); // all characters consumed
n = p.write( "3,4]" ); // parse the rest of the JSON
assert( n == 4 ); // all characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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);
/** Parse a buffer containing all or part of a complete JSON.
This function parses a all or part of a JSON
contained in the specified character buffer. The
entire buffer must be consumed; if there are
additional characters past the end of the complete
JSON, the parse fails and an error is returned.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write( "[1,2" ); // parse some of the JSON
assert( n == 4 ); // all characters consumed
n = p.write( "3,4]" ); // parse the rest of the JSON
assert( n == 4 ); // all characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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 all or part of a complete JSON.
This function parses a all or part of a JSON
contained in the specified character buffer. The
entire buffer must be consumed; if there are
additional characters past the end of the complete
JSON, the parse fails and an error is returned.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write( "[1,2" ); // parse some of the JSON
assert( n == 4 ); // all characters consumed
n = p.write( "3,4]" ); // parse the rest of the JSON
assert( n == 4 ); // all characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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);
}
/** Parse a buffer containing all or part of a complete JSON.
This function parses a all or part of a JSON
contained in the specified character buffer. The
entire buffer must be consumed; if there are
additional characters past the end of the complete
JSON, the parse fails and an error is returned.
@par Example
@code
stream_parser p; // construct a parser
std::size_t n; // number of characters used
n = p.write( "[1,2" ); // parse some of the JSON
assert( n == 4 ); // all characters consumed
n = p.write( "3,4]" ); // parse the rest of the JSON
assert( n == 4 ); // all characters consumed
value jv = p.release(); // take ownership of the value
@endcode
@note
To indicate there are no more character buffers,
such as when @ref done returns `false` after
writing, call @ref finish.
@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.
@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());
}
/** Indicate the end of JSON input.
This function is used to indicate that there
are no more character buffers in the current
JSON being parsed. If ther resulting JSON is
incomplete, the error is set to indicate a
parsing failure.
@par Example
In the code below, @ref finish is called to
indicate there are no more digits in the
resulting number:
@code
stream_parser p; // construct a parser
p.write( "3." ); // write the first part of the number
p.write( "14" ); // write the second part of the number
assert( ! p.done() ); // there could be more digits
p.finish(); // indicate the end of the JSON input
assert( p.done() ); // now we are finished
value jv = p.release(); // take ownership of the value
@endcode
@par Complexity
Constant.
@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.
@param ec Set to the error, if any occurred.
*/
BOOST_JSON_DECL
void
finish(error_code& ec);
/** Indicate the end of JSON input.
This function is used to indicate that there
are no more character buffers in the current
JSON being parsed. If ther resulting JSON is
incomplete, the error is set to indicate a
parsing failure.
@par Example
In the code below, @ref finish is called to
indicate there are no more digits in the
resulting number:
@code
stream_parser p; // construct a parser
p.write( "3." ); // write the first part of the number
p.write( "14" ); // write the second part of the number
assert( ! p.done() ); // there could be more digits
p.finish(); // indicate the end of the JSON input
assert( p.done() ); // now we are finished
value jv = p.release(); // take ownership of the value
@endcode
@par Complexity
Constant.
@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.
@throw system_error Thrown on error.
*/
BOOST_JSON_DECL
void
finish();
/** Return the parsed JSON 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.
@par Effects
@code
if( ! this->done() )
this->finish();
@endcode
@note
@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();
};
BOOST_JSON_NS_END
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
//
// 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_STRING_VIEW_HPP
#define BOOST_JSON_STRING_VIEW_HPP
#include <boost/json/detail/config.hpp>
#ifndef BOOST_JSON_STANDALONE
# include <boost/utility/string_view.hpp>
#else
# if __has_include(<string_view>)
# include <string_view>
# if __cpp_lib_string_view < 201603L
# error Support for std::string_view is required to use Boost.JSON standalone
# endif
# else
# error Header <string_view> is required to use Boost.JSON standalone
# endif
#endif
#include <type_traits>
BOOST_JSON_NS_BEGIN
#ifdef BOOST_JSON_DOCS
/** The type of string view used by the library.
This type alias is set depending
on how the library is configured:
@par Use with Boost
If the macro `BOOST_JSON_STANDALONE` is
not defined, this type will be an alias
for `boost::string_view`.
Compiling a program using the library will
require Boost, and a compiler conforming
to C++11 or later.
@par Use without Boost
If the macro `BOOST_JSON_STANDALONE` is
defined, this type will be an alias
for `std::string_view`.
Compiling a program using the library will
require only a compiler conforming to C++17
or later.
@see https://en.cppreference.com/w/cpp/string/basic_string_view
*/
using string_view = __see_below__;
#elif ! defined(BOOST_JSON_STANDALONE)
using string_view = boost::string_view;
#else
using string_view = std::string_view;
#endif
namespace detail {
template<class T>
using is_string_viewish = typename std::enable_if<
std::is_convertible<
T const&, string_view>::value &&
! std::is_convertible<
T const&, char const*>::value
>::type;
} // detail
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,57 @@
//
// 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_SYSTEM_ERROR_HPP
#define BOOST_JSON_SYSTEM_ERROR_HPP
#include <boost/json/detail/config.hpp>
#ifndef BOOST_JSON_STANDALONE
# include <boost/system/error_code.hpp>
# include <boost/system/system_error.hpp>
#else
# include <system_error>
#endif
BOOST_JSON_NS_BEGIN
#ifndef BOOST_JSON_STANDALONE
/// The type of error code used by the library.
using error_code = boost::system::error_code;
/// The type of error category used by the library.
using error_category = boost::system::error_category;
/// The type of error condition used by the library.
using error_condition = boost::system::error_condition;
/// The type of system error thrown by the library.
using system_error = boost::system::system_error;
#ifdef BOOST_JSON_DOCS
/// Returns the generic error category used by the library.
error_category const&
generic_category();
#else
using boost::system::generic_category;
#endif
#else
using error_code = std::error_code;
using error_category = std::error_category;
using error_condition = std::error_condition;
using system_error = std::system_error;
using std::generic_category;
#endif
BOOST_JSON_NS_END
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
//
// 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_VALUE_FROM_HPP
#define BOOST_JSON_VALUE_FROM_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/value_from.hpp>
BOOST_JSON_NS_BEGIN
/** 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>
*/
#ifndef BOOST_JSON_DOCS
struct value_from_tag;
#else
// VFALCO Doc toolchain doesn't like
// forward declared ordinary classes.
struct value_from_tag {};
#endif
/** Convert an object of type `T` to @ref value.
This function attempts to convert an object
of type `T` to @ref value using
@li one of @ref value's constructors,
@li a library-provided generic conversion, or
@li a user-provided overload of `tag_invoke`.
In all cases, the conversion is done by calling
an overload of `tag_invoke` found by argument-dependent
lookup. Its signature should be similar to:
@code
void tag_invoke( value_from_tag, value&, T );
@endcode
A @ref value constructed
with the @ref storage_ptr passed to @ref value_from is
passed as the second argument to ensure that the memory
resource is correctly propagated.
@par Exception Safety
Strong guarantee.
@tparam T The type of the object to convert.
@returns `t` converted to @ref value.
@param t The object to convert.
@param sp A storage pointer referring to the memory resource
to use for the returned @ref value. The default argument for this
parameter is `{}`.
@see @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>
value
value_from(
T&& t,
storage_ptr sp = {})
{
return detail::value_from_impl(
std::forward<T>(t), std::move(sp));
}
/** Determine if `T` can be converted to @ref value.
If `T` can be converted to @ref value via a
call to @ref value_from, the static data member `value`
is defined as `true`. Otherwise, `value` is
defined as `false`.
@see @ref value_from
*/
#ifdef BOOST_JSON_DOCS
template<class T>
using has_value_from = __see_below__;
#else
template<class T, class>
struct has_value_from : std::false_type { };
template<class T>
struct has_value_from<T, detail::void_t<
decltype(detail::value_from_impl(std::declval<T&&>(),
std::declval<storage_ptr>()))>>
: std::true_type { };
#endif
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,493 @@
//
// 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_VALUE_REF_HPP
#define BOOST_JSON_VALUE_REF_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/storage_ptr.hpp>
#include <boost/json/string.hpp>
#include <initializer_list>
#include <type_traits>
#include <utility>
BOOST_JSON_NS_BEGIN
#ifndef BOOST_JSON_DOCS
class value;
class object;
class array;
class string;
#endif
//----------------------------------------------------------
/** The type used in initializer lists.
This type is used in initializer lists for
lazy construction of and assignment to the
container types @ref value, @ref array,
and @ref object. The two types of initializer
lists used are:
@li `std::initializer_list< value_ref >` for
constructing or assigning a @ref value or
@ref array, and
@li `std::initializer_list< std::pair< string_view, value_ref > >`
for constructing or assigning an @ref object.
A `value_ref` uses reference semantics. Creation
of the actual container from the initializer
list is lazily deferred until the list is used.
This means that the @ref memory_resource used to
construct a container can be specified after the
point where the initializer list is specified.
@par Example
This example demonstrates how a user-defined type
containing a JSON value can be constructed from
an initializer list:
@code
class my_type
{
value jv_;
public:
my_type( std::initializer_list< value_ref > init )
: jv_(init)
{
}
};
@endcode
@note Never declare a variable of type
`std::initializer_list` except in function
parameter lists, otherwise the behavior may
be undefined.
@see
@ref value,
@ref array,
@ref object
*/
class value_ref
{
friend class value;
friend class object;
friend class array;
friend class value_ref_test;
enum class what
{
str,
ini,
func,
cfunc,
strfunc,
};
using init_list =
std::initializer_list<value_ref>;
struct func_type
{
value(*f)(void*, storage_ptr);
void* p;
};
struct cfunc_type
{
value(*f)(void const*, storage_ptr);
void const* p;
};
union arg_type
{
string_view str_;
init_list init_list_;
signed char schar_;
short short_;
int int_;
long long_;
long long long_long_;
unsigned char uchar_;
unsigned short ushort_;
unsigned int uint_;
unsigned long ulong_;
unsigned long long ulong_long_;
float float_;
double double_;
bool bool_;
std::nullptr_t nullptr_;
arg_type() {}
explicit arg_type(string_view t) noexcept : str_(t) {}
explicit arg_type(init_list t) noexcept : init_list_(t) {}
explicit arg_type(signed char t) noexcept : schar_(t) {}
explicit arg_type(short t) noexcept : short_(t) {}
explicit arg_type(int t) noexcept : int_(t) {}
explicit arg_type(long t) noexcept : long_(t) {}
explicit arg_type(long long t) noexcept : long_long_(t) {}
explicit arg_type(unsigned char t) noexcept : uchar_(t) {}
explicit arg_type(unsigned short t) noexcept : ushort_(t) {}
explicit arg_type(unsigned int t) noexcept : uint_(t) {}
explicit arg_type(unsigned long t) noexcept : ulong_(t) {}
explicit arg_type(unsigned long long t) noexcept : ulong_long_(t) {}
explicit arg_type(float t) noexcept : float_(t) {}
explicit arg_type(double t) noexcept : double_(t) {}
explicit arg_type(bool t) noexcept : bool_(t) {}
explicit arg_type(std::nullptr_t) noexcept : nullptr_() {}
};
template<class T>
using is_builtin =
std::integral_constant<bool,
std::is_same<T, signed char>::value ||
std::is_same<T, short>::value ||
std::is_same<T, int>::value ||
std::is_same<T, long>::value ||
std::is_same<T, long long>::value ||
std::is_same<T, unsigned char>::value ||
std::is_same<T, unsigned short>::value ||
std::is_same<T, unsigned int>::value ||
std::is_same<T, unsigned long>::value ||
std::is_same<T, unsigned long long>::value ||
std::is_same<T, float>::value ||
std::is_same<T, double>::value ||
std::is_same<T, std::nullptr_t>::value>;
arg_type arg_;
#ifndef BOOST_JSON_DOCS
// VFALCO doc toolchain erroneously
// displays private, anonymous unions as public
union
{
func_type f_;
cfunc_type cf_;
};
#endif
what what_;
public:
/// Constructor
value_ref(
value_ref const&) = default;
/// Constructor
#ifdef BOOST_JSON_DOCS
value_ref(string_view s) noexcept;
#else
template<
class T
,class = typename
std::enable_if<
std::is_constructible<
string_view, T>::value>::type
>
value_ref(
T const& t) noexcept
: arg_(string_view(t))
, what_(what::str)
{
}
#endif
/// Constructor
template<class T>
value_ref(
T const& t
#ifndef BOOST_JSON_DOCS
,typename std::enable_if<
! std::is_constructible<
string_view, T>::value &&
! std::is_same<bool, T>::value
>::type* = 0
#endif
) noexcept
: cf_{&from_const<T>, &t}
, what_(what::cfunc)
{
}
/// Constructor
template<class T>
value_ref(
T&& t
#ifndef BOOST_JSON_DOCS
,typename std::enable_if<
(! std::is_constructible<
string_view, T>::value ||
std::is_same<string, T>::value) &&
! std::is_same<bool,
detail::remove_cvref<T>>::value &&
std::is_same<T, detail::remove_cvref<T>>
::value>::type* = 0
#endif
) noexcept
: f_{&from_rvalue<
detail::remove_cvref<T>>, &t}
, what_(std::is_same<string, T>::value ?
what::strfunc : what::func)
{
}
/// Constructor
#ifdef BOOST_JSON_DOCS
value_ref(bool b) noexcept;
#else
template<
class Bool
,class = typename std::enable_if<
std::is_same<Bool, bool>::value>::type
>
value_ref(
Bool b) noexcept
: arg_(b)
, cf_{&from_builtin<bool>, &arg_.bool_}
, what_(what::cfunc)
{
}
#endif
/// Constructor
value_ref(
std::initializer_list<
value_ref> t) noexcept
: arg_(t)
, what_(what::ini)
{
}
/// Constructor
value_ref(signed char t) noexcept
: arg_(t)
, cf_{&from_builtin<signed char>, &arg_.schar_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(short t) noexcept
: arg_(t)
, cf_{&from_builtin<short>, &arg_.short_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(int t) noexcept
: arg_(t)
, cf_{&from_builtin<int>, &arg_.int_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(long t) noexcept
: arg_(t)
, cf_{&from_builtin<
long>, &arg_.long_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(long long t) noexcept
: arg_(t)
, cf_{&from_builtin<
long long>, &arg_.long_long_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(unsigned char t) noexcept
: arg_(t)
, cf_{&from_builtin<
unsigned char>, &arg_.uchar_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(unsigned short t) noexcept
: arg_(t)
, cf_{&from_builtin<
unsigned short>, &arg_.ushort_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(unsigned int t) noexcept
: arg_(t)
, cf_{&from_builtin<
unsigned int>, &arg_.uint_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(unsigned long t) noexcept
: arg_(t)
, cf_{&from_builtin<
unsigned long>, &arg_.ulong_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(unsigned long long t) noexcept
: arg_(t)
, cf_{&from_builtin<
unsigned long long>, &arg_.ulong_long_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(float t) noexcept
: arg_(t)
, cf_{&from_builtin<
float>, &arg_.float_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(double t) noexcept
: arg_(t)
, cf_{&from_builtin<
double>, &arg_.double_}
, what_(what::cfunc)
{
}
/// Constructor
value_ref(std::nullptr_t) noexcept
: arg_(nullptr)
, cf_{&from_builtin<
std::nullptr_t>, &arg_.nullptr_}
, what_(what::cfunc)
{
}
#ifndef BOOST_JSON_DOCS
// Not public
//private:
// VFALCO Why is this needed?
/** Operator conversion to @ref value
This allows creation of a @ref value from
an initializer list element.
*/
BOOST_JSON_DECL
operator value() const;
#endif
private:
template<class T>
static
value
from_builtin(
void const* p,
storage_ptr sp) noexcept;
template<class T>
static
value
from_const(
void const* p,
storage_ptr sp);
template<class T>
static
value
from_rvalue(
void* p,
storage_ptr sp);
static
BOOST_JSON_DECL
value
from_init_list(
void const* p,
storage_ptr sp);
inline
bool
is_key_value_pair() const noexcept;
static
inline
bool
maybe_object(
std::initializer_list<
value_ref> init) noexcept;
inline
string_view
get_string() const noexcept;
BOOST_JSON_DECL
value
make_value(
storage_ptr sp) const;
BOOST_JSON_DECL
static
value
make_value(
std::initializer_list<
value_ref> init,
storage_ptr sp);
BOOST_JSON_DECL
static
object
make_object(
std::initializer_list<value_ref> init,
storage_ptr sp);
BOOST_JSON_DECL
static
array
make_array(
std::initializer_list<
value_ref> init,
storage_ptr sp);
BOOST_JSON_DECL
static
void
write_array(
value* dest,
std::initializer_list<
value_ref> init,
storage_ptr const& sp);
};
BOOST_JSON_NS_END
// Must be included here for this file to stand alone
#include <boost/json/value.hpp>
// includes are at the bottom of <boost/json/value.hpp>
//#include <boost/json/impl/value.hpp>
//#include <boost/json/impl/value.ipp>
#endif

View File

@@ -0,0 +1,508 @@
//
// 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_VALUE_STACK_HPP
#define BOOST_JSON_VALUE_STACK_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/error.hpp>
#include <boost/json/storage_ptr.hpp>
#include <boost/json/value.hpp>
#include <stddef.h>
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
/** A stack of @ref value elements, for building a document.
This stack of @ref value allows iterative
construction of a JSON document in memory.
The implementation uses temporary internal
storage to buffer elements so that arrays, objects,
and strings in the document are constructed using a
single memory allocation. This improves performance
and makes efficient use of the @ref memory_resource
used to create the resulting @ref value.
Temporary storage used by the implementation
initially comes from an optional memory buffer
owned by the caller. If that storage is exhausted,
then memory is obtained dynamically from the
@ref memory_resource provided on construction.
@par Usage
Construct the stack with an optional initial
temporary buffer, and a @ref storage_ptr to use for
more storage when the initial buffer is exhausted.
Then to build a @ref value, first call @ref reset
and optionally specify the @ref memory_resource
which will be used for the value. Then push elements
onto the stack by calling the corresponding functions.
After the document has been fully created, call
@ref release to acquire ownership of the top-level
@ref value.
@par Performance
The initial buffer and any dynamically allocated
temporary buffers are retained until the stack
is destroyed. This improves performance when using
a single stack instance to produce multiple
values.
@par Example
The following code constructs a @ref value which
when serialized produces a JSON object with three
elements. It uses a local buffer for the temporary
storage, and a separate local buffer for the storage
of the resulting value. No memory is dynamically
allocated; this shows how to construct a value
without using the heap.
@code
// This example builds a json::value without any dynamic memory allocations:
// Construct the value stack using a local buffer
unsigned char temp[4096];
value_stack st( storage_ptr(), temp, sizeof(temp) );
// Create a static resource with a local initial buffer
unsigned char buf[4096];
static_resource mr( buf, sizeof(buf) );
// All values on the stack will use `mr`
st.reset(&mr);
// Push the key/value pair "a":1.
st.push_key("a");
st.push_int64(1);
// Push "b":null
st.push_key("b");
st.push_null();
// Push "c":"hello"
st.push_key("c");
st.push_string("hello");
// Pop the three key/value pairs and push an object with those three values.
st.push_object(3);
// Pop the object from the stack and take ownership.
value jv = st.release();
assert( serialize(jv) == "{\"a\":1,\"b\":null,\"c\":\"hello\"}" );
// At this point we could re-use the stack by calling reset
@endcode
@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.
*/
class value_stack
{
class stack
{
enum
{
min_size_ = 16
};
storage_ptr sp_;
void* temp_;
value* begin_;
value* top_;
value* end_;
// string starts at top_+1
std::size_t chars_ = 0;
bool run_dtors_ = true;
public:
inline ~stack();
inline stack(
storage_ptr sp,
void* temp, std::size_t size) noexcept;
inline void run_dtors(bool b) noexcept;
inline std::size_t size() const noexcept;
inline bool has_chars();
inline void clear() noexcept;
inline void maybe_grow();
inline void grow_one();
inline void grow(std::size_t nchars);
inline void append(string_view s);
inline string_view release_string() noexcept;
inline value* release(std::size_t n) noexcept;
template<class... Args> value& push(Args&&... args);
template<class Unchecked> void exchange(Unchecked&& u);
};
stack st_;
storage_ptr sp_;
public:
/// Copy constructor (deleted)
value_stack(
value_stack const&) = delete;
/// Copy assignment (deleted)
value_stack& operator=(
value_stack const&) = delete;
/** Destructor.
All dynamically allocated memory and
partial or complete elements is freed.
@par Complexity
Linear in the size of partial results.
@par Exception Safety
No-throw guarantee.
*/
BOOST_JSON_DECL
~value_stack();
/** Constructor.
Constructs an empty stack. Before any
@ref value can be built, the function
@ref reset must be called.
The `sp` parameter is only used to allocate
intermediate storage; it will not be used
for the @ref value returned by @ref release.
@param sp A pointer to the @ref memory_resource
to use for intermediate storage allocations. If
this argument is omitted, the default memory
resource is used.
@param temp_buffer A pointer to a caller-owned
buffer which will be used to store temporary
data used while building the value. If this
pointer is null, the builder will use the
storage pointer to allocate temporary data.
@param temp_size The number of valid bytes of
storage pointed to by `temp_buffer`.
*/
BOOST_JSON_DECL
value_stack(
storage_ptr sp = {},
unsigned char* temp_buffer = nullptr,
std::size_t temp_size = 0) noexcept;
/** Prepare to build a new document.
This function must be called before constructing
a new top-level @ref value. Any previously existing
partial or complete elements are destroyed, but
internal dynamically allocated memory is preserved
which may be reused to build new values.
@par Exception Safety
No-throw guarantee.
@param sp A pointer to the @ref memory_resource
to use for top-level @ref value and all child
values. The stack will acquire shared ownership
of the memory resource until @ref release or
@ref reset is called, or when the stack is
destroyed.
*/
BOOST_JSON_DECL
void
reset(storage_ptr sp = {}) noexcept;
/** Return the top-level @ref value.
This function transfers ownership of the
constructed top-level value to the caller.
The behavior is undefined if there is not
a single, top-level element.
@par Exception Safety
No-throw guarantee.
@return A __value__ holding the result.
Ownership of this value is transferred
to the caller. Ownership of the memory
resource used in the last call to @ref reset
is released.
*/
BOOST_JSON_DECL
value
release() noexcept;
//--------------------------------------------
/** Push an array formed by popping `n` values from the stack.
This function pushes an @ref array value
onto the stack. The array is formed by first
popping the top `n` values from the stack.
If the stack contains fewer than `n` values,
or if any of the top `n` values on the stack
is a key, the behavior is undefined.
@par Example
The following statements produce an array
with the contents 1, 2, 3:
@code
value_stack st;
// reset must be called first or else the behavior is undefined
st.reset();
// Place three values on the stack
st.push_int64( 1 );
st.push_int64( 2 );
st.push_int64( 3 );
// Remove the 3 values, and push an array with those 3 elements on the stack
st.push_array( 3 );
// Pop the object from the stack and take ownership.
value jv = st.release();
assert( serialize(jv) == "[1,2,3]" );
// At this point, reset must be called again to use the stack
@endcode
@param n The number of values to pop from the
top of the stack to form the array.
*/
BOOST_JSON_DECL
void
push_array(std::size_t n);
/** Push an object formed by popping `n` key/value pairs from the stack.
This function pushes an @ref object value
onto the stack. The object is formed by first
popping the top `n` key/value pairs from the
stack. If the stack contains fewer than `n`
key/value pairs, or if any of the top `n` key/value
pairs on the stack does not consist of exactly one
key followed by one value, the behavior is undefined.
@note
A key/value pair is formed by pushing a key, and then
pushing a value.
@par Example
The following code creates an object on the stack
with a single element, where key is "x" and value
is true:
@code
value_stack st;
// reset must be called first or else the behavior is undefined
st.reset();
// Place a key/value pair onto the stack
st.push_key( "x" );
st.push_bool( true );
// Replace the key/value pair with an object containing a single element
st.push_object( 1 );
// Pop the object from the stack and take ownership.
value jv = st.release();
assert( serialize(jv) == "{\"x\",true}" );
// At this point, reset must be called again to use the stack
@endcode
@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.
@param n The number of key/value pairs to pop from the
top of the stack to form the array.
*/
BOOST_JSON_DECL
void
push_object(std::size_t n);
/** Push part of a key or string onto the stack.
This function pushes the characters in `s` onto
the stack, appending to any existing characters
or creating new characters as needed. Once a
string part is placed onto the stack, the only
valid stack operations are:
@li @ref push_chars to append additional
characters to the key or string being built,
@li @ref push_key or @ref push_string to
finish building the key or string and place
the value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
*/
BOOST_JSON_DECL
void
push_chars(
string_view s);
/** Push a key onto the stack.
This function notionally removes all the
characters currently on the stack, then
pushes a @ref value containing a key onto
the stack formed by appending `s` to the
removed characters.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
*/
BOOST_JSON_DECL
void
push_key(
string_view s);
/** Place a string value onto the stack.
This function notionally removes all the
characters currently on the stack, then
pushes a @ref value containing a @ref string
onto the stack formed by appending `s` to the
removed characters.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
*/
BOOST_JSON_DECL
void
push_string(
string_view s);
/** Push a number onto the stack
This function pushes a number value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param i The number to insert.
*/
BOOST_JSON_DECL
void
push_int64(
int64_t i);
/** Push a number onto the stack
This function pushes a number value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param u The number to insert.
*/
BOOST_JSON_DECL
void
push_uint64(
uint64_t u);
/** Push a number onto the stack
This function pushes a number value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param d The number to insert.
*/
BOOST_JSON_DECL
void
push_double(
double d);
/** Push a `bool` onto the stack
This function pushes a boolean value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
@param b The boolean to insert.
*/
BOOST_JSON_DECL
void
push_bool(
bool b);
/** Push a null onto the stack
This function pushes a boolean value onto the stack.
@par Exception Safety
Basic guarantee.
Calls to `memory_resource::allocate` may throw.
*/
BOOST_JSON_DECL
void
push_null();
};
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,123 @@
//
// 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_VALUE_TO_HPP
#define BOOST_JSON_VALUE_TO_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/value_to.hpp>
BOOST_JSON_NS_BEGIN
/** 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;
/** Convert a @ref value to an object of type `T`.
This function attempts to convert a @ref value
to `T` using
@li one of @ref value's accessors, or
@li a library-provided generic conversion, or
@li a user-provided overload of `tag_invoke`.
In all cases, the conversion is done by calling
an overload of `tag_invoke` found by argument-dependent
lookup. Its signature should be similar to:
@code
T tag_invoke( value_to_tag<T>, value );
@endcode
The object returned by the function call is
returned by @ref value_to as the result of the
conversion.
@par Constraints
@code
! std::is_reference< T >::value
@endcode
@par Exception Safety
Strong guarantee.
@tparam T The type to convert to.
@returns `jv` converted to `T`.
@param jv The @ref value to convert.
@see @ref value_to_tag, @ref value_from,
<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>
*/
#ifdef BOOST_JSON_DOCS
template<class T>
T
value_to(const value& jv);
#else
template<class T, class U
, typename std::enable_if<
! std::is_reference<T>::value &&
std::is_same<U, value>::value>::type*
>
T
value_to(const U& jv)
{
return detail::value_to_impl(
value_to_tag<typename std::remove_cv<T>::type>(), jv);
}
#endif
/** Determine a @ref value can be converted to `T`.
If @ref value can be converted to `T` via a
call to @ref value_to, the static data member `value`
is defined as `true`. Otherwise, `value` is
defined as `false`.
@see @ref value_to
*/
#ifdef BOOST_JSON_DOCS
template<class T>
using has_value_to = __see_below__;
#else
template<class T, class>
struct has_value_to
: std::false_type { };
template<class T>
struct has_value_to<T, detail::void_t<decltype(
detail::value_to_impl(
value_to_tag<detail::remove_cvref<T>>(),
std::declval<const value&>())),
typename std::enable_if<
! std::is_reference<T>::value>::type
> > : std::true_type { };
#endif
BOOST_JSON_NS_END
#endif

View File

@@ -0,0 +1,48 @@
//
// 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_VISIT_HPP
#define BOOST_JSON_VISIT_HPP
#include <boost/json/detail/config.hpp>
#include <boost/json/value.hpp>
#include <type_traits>
#include <utility>
BOOST_JSON_NS_BEGIN
/** Invoke a function object with the contents of a @ref value
@return The value returned by Visitor.
@param v The visitation function to invoke
@param jv The value to visit.
*/
/** @{ */
template<class Visitor>
auto
visit(
Visitor&& v,
value& jv) -> decltype(
std::declval<Visitor>()(nullptr));
template<class Visitor>
auto
visit(
Visitor &&v,
value const &jv) -> decltype(
std::declval<Visitor>()(nullptr));
/** @} */
BOOST_JSON_NS_END
#include <boost/json/impl/visit.hpp>
#endif