update to json=3.9.1, doctest=2.4.6
diff --git a/third_party/include/doctest/LICENSE.txt b/third_party/include/doctest/LICENSE.txt
index 6117758..c027373 100644
--- a/third_party/include/doctest/LICENSE.txt
+++ b/third_party/include/doctest/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2016-2019 Viktor Kirilov
+Copyright (c) 2016-2021 Viktor Kirilov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/third_party/include/doctest/doctest.h b/third_party/include/doctest/doctest.h
index c6bcafe..880e5bf 100644
--- a/third_party/include/doctest/doctest.h
+++ b/third_party/include/doctest/doctest.h
@@ -4,7 +4,7 @@
//
// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD
//
-// Copyright (c) 2016-2019 Viktor Kirilov
+// Copyright (c) 2016-2021 Viktor Kirilov
//
// Distributed under the MIT Software License
// See accompanying file LICENSE.txt or copy at
@@ -47,9 +47,9 @@
// =================================================================================================
#define DOCTEST_VERSION_MAJOR 2
-#define DOCTEST_VERSION_MINOR 3
-#define DOCTEST_VERSION_PATCH 7
-#define DOCTEST_VERSION_STR "2.3.7"
+#define DOCTEST_VERSION_MINOR 4
+#define DOCTEST_VERSION_PATCH 6
+#define DOCTEST_VERSION_STR "2.4.6"
#define DOCTEST_VERSION \
(DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH)
@@ -301,11 +301,23 @@
#define DOCTEST_NOINLINE __declspec(noinline)
#define DOCTEST_UNUSED
#define DOCTEST_ALIGNMENT(x)
-#else // MSVC
+#elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0)
+#define DOCTEST_NOINLINE
+#define DOCTEST_UNUSED
+#define DOCTEST_ALIGNMENT(x)
+#else
#define DOCTEST_NOINLINE __attribute__((noinline))
#define DOCTEST_UNUSED __attribute__((unused))
#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x)))
-#endif // MSVC
+#endif
+
+#ifndef DOCTEST_NORETURN
+#define DOCTEST_NORETURN [[noreturn]]
+#endif // DOCTEST_NORETURN
+
+#ifndef DOCTEST_NOEXCEPT
+#define DOCTEST_NOEXCEPT noexcept
+#endif // DOCTEST_NOEXCEPT
// =================================================================================================
// == FEATURE DETECTION END ========================================================================
@@ -342,13 +354,25 @@
#define DOCTEST_GLOBAL_NO_WARNINGS(var) \
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \
- static int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp)
+ static const int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp)
#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP
#ifndef DOCTEST_BREAK_INTO_DEBUGGER
// should probably take a look at https://github.com/scottt/debugbreak
-#ifdef DOCTEST_PLATFORM_MAC
-#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :)
+#ifdef DOCTEST_PLATFORM_LINUX
+#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
+// Break at the location of the failing check if possible
+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
+#else
+#include <signal.h>
+#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP)
+#endif
+#elif defined(DOCTEST_PLATFORM_MAC)
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386)
+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
+#else
+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT (hicpp-no-assembler)
+#endif
#elif DOCTEST_MSVC
#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak()
#elif defined(__MINGW32__)
@@ -357,7 +381,7 @@
DOCTEST_GCC_SUPPRESS_WARNING_POP
#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak()
#else // linux
-#define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0)
+#define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast<void>(0))
#endif // linux
#endif // DOCTEST_BREAK_INTO_DEBUGGER
@@ -367,6 +391,9 @@
#endif // DOCTEST_CONFIG_USE_IOSFWD
#ifdef DOCTEST_CONFIG_USE_STD_HEADERS
+#ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
+#define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
+#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
#include <iosfwd>
#include <cstddef>
#include <ostream>
@@ -629,12 +656,14 @@
struct DOCTEST_INTERFACE TestCaseData
{
- const char* m_file; // the file in which the test was registered
+ String m_file; // the file in which the test was registered (using String - see #350)
unsigned m_line; // the line where the test was registered
const char* m_name; // name of the test case
const char* m_test_suite; // the test suite in which the test was added
const char* m_description;
bool m_skip;
+ bool m_no_breaks;
+ bool m_no_output;
bool m_may_fail;
bool m_should_fail;
int m_expected_failures;
@@ -688,12 +717,18 @@
virtual void stringify(std::ostream*) const = 0;
};
+namespace detail {
+ struct DOCTEST_INTERFACE TestCase;
+} // namespace detail
+
struct ContextOptions //!OCLINT too many fields
{
std::ostream* cout; // stdout stream - std::cout by default
std::ostream* cerr; // stderr stream - std::cerr by default
String binary_name; // the test binary name
+ const detail::TestCase* currentTest = nullptr;
+
// == parameters from the command line
String out; // output filename
String order_by; // how tests should be ordered
@@ -720,7 +755,9 @@
bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x):
bool no_path_in_filenames; // if the path to files should be removed from the output
bool no_line_numbers; // if source code line numbers should be omitted from the output
+ bool no_debug_output; // no output in the debug console when a debugger is attached
bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!!
+ bool no_time_in_output; // omit any time/timestamps from output !!! UNDOCUMENTED !!!
bool help; // to print the help
bool version; // to print the version
@@ -731,7 +768,6 @@
};
namespace detail {
-#if defined(DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || defined(DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS)
template <bool CONDITION, typename TYPE = void>
struct enable_if
{};
@@ -739,15 +775,45 @@
template <typename TYPE>
struct enable_if<true, TYPE>
{ typedef TYPE type; };
-#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
// clang-format off
template<class T> struct remove_reference { typedef T type; };
template<class T> struct remove_reference<T&> { typedef T type; };
template<class T> struct remove_reference<T&&> { typedef T type; };
+ template<typename T, typename U = T&&> U declval(int);
+
+ template<typename T> T declval(long);
+
+ template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ;
+
+ template<class T> struct is_lvalue_reference { const static bool value=false; };
+ template<class T> struct is_lvalue_reference<T&> { const static bool value=true; };
+
+ template <class T>
+ inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT
+ {
+ return static_cast<T&&>(t);
+ }
+
+ template <class T>
+ inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT
+ {
+ static_assert(!is_lvalue_reference<T>::value,
+ "Can not forward an rvalue as an lvalue.");
+ return static_cast<T&&>(t);
+ }
+
template<class T> struct remove_const { typedef T type; };
template<class T> struct remove_const<const T> { typedef T type; };
+#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
+ template<class T> struct is_enum : public std::is_enum<T> {};
+ template<class T> struct underlying_type : public std::underlying_type<T> {};
+#else
+ // Use compiler intrinsics
+ template<class T> struct is_enum { constexpr static bool value = __is_enum(T); };
+ template<class T> struct underlying_type { typedef __underlying_type(T) type; };
+#endif
// clang-format on
template <typename T>
@@ -756,33 +822,23 @@
{ static const bool value = false; };
namespace has_insertion_operator_impl {
- typedef char no;
- typedef char yes[2];
+ std::ostream &os();
+ template<class T>
+ DOCTEST_REF_WRAP(T) val();
- struct any_t
- {
- template <typename T>
- // cppcheck-suppress noExplicitConstructor
- any_t(const DOCTEST_REF_WRAP(T));
+ template<class, class = void>
+ struct check {
+ static constexpr bool value = false;
};
- yes& testStreamable(std::ostream&);
- no testStreamable(no);
-
- no operator<<(const std::ostream&, const any_t&);
-
- template <typename T>
- struct has_insertion_operator
- {
- static std::ostream& s;
- static const DOCTEST_REF_WRAP(T) t;
- static const bool value = sizeof(decltype(testStreamable(s << t))) == sizeof(yes);
+ template<class T>
+ struct check<T, decltype(os() << val<T>(), void())> {
+ static constexpr bool value = true;
};
} // namespace has_insertion_operator_impl
- template <typename T>
- struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator<T>
- {};
+ template<class T>
+ using has_insertion_operator = has_insertion_operator_impl::check<const T>;
DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num);
@@ -846,7 +902,7 @@
}
};
-template <typename T>
+template <typename T, typename detail::enable_if<!detail::is_enum<T>::value, bool>::type = true>
String toString(const DOCTEST_REF_WRAP(T) value) {
return StringMaker<T>::convert(value);
}
@@ -873,6 +929,12 @@
DOCTEST_INTERFACE String toString(int long long unsigned in);
DOCTEST_INTERFACE String toString(std::nullptr_t in);
+template <typename T, typename detail::enable_if<detail::is_enum<T>::value, bool>::type = true>
+String toString(const DOCTEST_REF_WRAP(T) value) {
+ typedef typename detail::underlying_type<T>::type UT;
+ return toString(static_cast<UT>(value));
+}
+
#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0)
// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183
DOCTEST_INTERFACE String toString(const std::string& in);
@@ -987,7 +1049,7 @@
DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at);
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
- [[noreturn]]
+ DOCTEST_NORETURN
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
DOCTEST_INTERFACE void throwException();
@@ -1005,13 +1067,24 @@
template <typename L, typename R>
String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op,
const DOCTEST_REF_WRAP(R) rhs) {
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
return toString(lhs) + op + toString(rhs);
}
+#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
+DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
+#endif
+
+// This will check if there is any way it could find a operator like member or friend and uses it.
+// If not it doesn't find the operator or if the operator at global scope is defined after
+// this template, the template won't be instantiated due to SFINAE. Once the template is not
+// instantiated it can look for global operator using normal conversions.
+#define SFINAE_OP(ret,op) decltype(doctest::detail::declval<L>() op doctest::detail::declval<R>(),static_cast<ret>(0))
+
#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \
template <typename R> \
- DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \
- bool res = op_macro(lhs, rhs); \
+ DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) { \
+ bool res = op_macro(doctest::detail::forward<L>(lhs), doctest::detail::forward<R>(rhs)); \
if(m_at & assertType::is_false) \
res = !res; \
if(!res || doctest::getContextOptions()->success) \
@@ -1092,6 +1165,7 @@
#define DOCTEST_COMPARISON_RETURN_TYPE bool
#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if<can_use_op<L>::value || can_use_op<R>::value, bool>::type
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); }
inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); }
inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); }
@@ -1138,12 +1212,16 @@
L lhs;
assertType::Enum m_at;
- explicit Expression_lhs(L in, assertType::Enum at)
- : lhs(in)
+ explicit Expression_lhs(L&& in, assertType::Enum at)
+ : lhs(doctest::detail::forward<L>(in))
, m_at(at) {}
DOCTEST_NOINLINE operator Result() {
- bool res = !!lhs;
+// this is needed only foc MSVC 2015:
+// https://ci.appveyor.com/project/onqtam/doctest/builds/38181202
+DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool
+ bool res = static_cast<bool>(lhs);
+DOCTEST_MSVC_SUPPRESS_WARNING_POP
if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional
res = !res;
@@ -1152,6 +1230,10 @@
return Result(res);
}
+ /* This is required for user-defined conversions from Expression_lhs to L */
+ //operator L() const { return lhs; }
+ operator L() const { return lhs; }
+
// clang-format off
DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional
DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional
@@ -1192,6 +1274,10 @@
#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION
+#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
+DOCTEST_CLANG_SUPPRESS_WARNING_POP
+#endif
+
struct DOCTEST_INTERFACE ExpressionDecomposer
{
assertType::Enum m_at;
@@ -1203,8 +1289,8 @@
// https://github.com/catchorg/Catch2/issues/870
// https://github.com/catchorg/Catch2/issues/565
template <typename L>
- Expression_lhs<const DOCTEST_REF_WRAP(L)> operator<<(const DOCTEST_REF_WRAP(L) operand) {
- return Expression_lhs<const DOCTEST_REF_WRAP(L)>(operand, m_at);
+ Expression_lhs<L> operator<<(L &&operand) {
+ return Expression_lhs<L>(doctest::detail::forward<L>(operand), m_at);
}
};
@@ -1213,6 +1299,8 @@
const char* m_test_suite;
const char* m_description;
bool m_skip;
+ bool m_no_breaks;
+ bool m_no_output;
bool m_may_fail;
bool m_should_fail;
int m_expected_failures;
@@ -1284,12 +1372,12 @@
template <class L, class R> struct RelationalComparator<n, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } };
// clang-format on
- DOCTEST_BINARY_RELATIONAL_OP(0, eq)
- DOCTEST_BINARY_RELATIONAL_OP(1, ne)
- DOCTEST_BINARY_RELATIONAL_OP(2, gt)
- DOCTEST_BINARY_RELATIONAL_OP(3, lt)
- DOCTEST_BINARY_RELATIONAL_OP(4, ge)
- DOCTEST_BINARY_RELATIONAL_OP(5, le)
+ DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq)
+ DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne)
+ DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt)
+ DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt)
+ DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge)
+ DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le)
struct DOCTEST_INTERFACE ResultBuilder : public AssertData
{
@@ -1416,9 +1504,9 @@
} catch(T ex) { // NOLINT
res = m_translateFunction(ex); //!OCLINT parameter reassignment
return true;
- } catch(...) {} //!OCLINT - empty catch statement
-#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
- ((void)res); // to silence -Wunused-parameter
+ } catch(...) {} //!OCLINT - empty catch statement
+#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
+ static_cast<void>(res); // to silence -Wunused-parameter
return false;
}
@@ -1491,7 +1579,7 @@
template <typename L> class ContextScope : public ContextScopeBase
{
- const L &lambda_;
+ const L lambda_;
public:
explicit ContextScope(const L &lambda) : lambda_(lambda) {}
@@ -1511,12 +1599,24 @@
MessageBuilder() = delete;
~MessageBuilder();
+ // the preferred way of chaining parameters for stringification
template <typename T>
- MessageBuilder& operator<<(const T& in) {
+ MessageBuilder& operator,(const T& in) {
toStream(m_stream, in);
return *this;
}
+ // kept here just for backwards-compatibility - the comma operator should be preferred now
+ template <typename T>
+ MessageBuilder& operator<<(const T& in) { return this->operator,(in); }
+
+ // the `,` operator has the lowest operator precedence - if `<<` is used by the user then
+ // the `,` operator will be called last which is not what we want and thus the `*` operator
+ // is used first (has higher operator precedence compared to `<<`) so that we guarantee that
+ // an operator of the MessageBuilder class is called first before the rest of the parameters
+ template <typename T>
+ MessageBuilder& operator*(const T& in) { return this->operator,(in); }
+
bool log();
void react();
};
@@ -1540,6 +1640,8 @@
DOCTEST_DEFINE_DECORATOR(test_suite, const char*, "");
DOCTEST_DEFINE_DECORATOR(description, const char*, "");
DOCTEST_DEFINE_DECORATOR(skip, bool, true);
+DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true);
+DOCTEST_DEFINE_DECORATOR(no_output, bool, true);
DOCTEST_DEFINE_DECORATOR(timeout, double, 0);
DOCTEST_DEFINE_DECORATOR(may_fail, bool, true);
DOCTEST_DEFINE_DECORATOR(should_fail, bool, true);
@@ -1737,12 +1839,12 @@
#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS
#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS
-#define DOCTEST_CAST_TO_VOID(x) \
+#define DOCTEST_CAST_TO_VOID(...) \
DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \
- static_cast<void>(x); \
+ static_cast<void>(__VA_ARGS__); \
DOCTEST_GCC_SUPPRESS_WARNING_POP
#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS
-#define DOCTEST_CAST_TO_VOID(x) x;
+#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__;
#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS
// registers the test by initializing a dummy var with a function
@@ -1876,10 +1978,12 @@
static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \
- static doctest::detail::TestSuite data; \
+ DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \
+ static doctest::detail::TestSuite data{}; \
static bool inited = false; \
DOCTEST_MSVC_SUPPRESS_WARNING_POP \
DOCTEST_CLANG_SUPPRESS_WARNING_POP \
+ DOCTEST_GCC_SUPPRESS_WARNING_POP \
if(!inited) { \
data* decorators; \
inited = true; \
@@ -1932,38 +2036,36 @@
DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
// for logging
-#define DOCTEST_INFO(expression) \
+#define DOCTEST_INFO(...) \
DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \
- DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), expression)
+ __VA_ARGS__)
-#define DOCTEST_INFO_IMPL(lambda_name, mb_name, s_name, expression) \
- DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \
- auto lambda_name = [&](std::ostream* s_name) { \
+#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \
+ auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \
+ [&](std::ostream* s_name) { \
doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \
mb_name.m_stream = s_name; \
- mb_name << expression; \
- }; \
- DOCTEST_MSVC_SUPPRESS_WARNING_POP \
- auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(lambda_name)
+ mb_name * __VA_ARGS__; \
+ })
-#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := " << x)
+#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x)
-#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, x) \
+#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...) \
do { \
doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \
- mb << x; \
+ mb * __VA_ARGS__; \
DOCTEST_ASSERT_LOG_AND_REACT(mb); \
- } while((void)0, 0)
+ } while(false)
// clang-format off
-#define DOCTEST_ADD_MESSAGE_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x)
-#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x)
-#define DOCTEST_ADD_FAIL_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x)
+#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
+#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
+#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__)
// clang-format on
-#define DOCTEST_MESSAGE(x) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, x)
-#define DOCTEST_FAIL_CHECK(x) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, x)
-#define DOCTEST_FAIL(x) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, x)
+#define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__)
+#define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__)
+#define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__)
#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility.
@@ -1982,7 +2084,7 @@
#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \
do { \
DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \
- } while((void)0, 0)
+ } while(false)
#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS
@@ -2006,12 +2108,12 @@
#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__)
// clang-format off
-#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } while((void)0, 0)
-#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } while((void)0, 0)
-#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } while((void)0, 0)
-#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } while((void)0, 0)
-#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } while((void)0, 0)
-#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while((void)0, 0)
+#define DOCTEST_WARN_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } while(false)
+#define DOCTEST_CHECK_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } while(false)
+#define DOCTEST_REQUIRE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } while(false)
+#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } while(false)
+#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } while(false)
+#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while(false)
// clang-format on
#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \
@@ -2021,73 +2123,73 @@
__LINE__, #expr, #__VA_ARGS__, message); \
try { \
DOCTEST_CAST_TO_VOID(expr) \
- } catch(const doctest::detail::remove_const< \
- doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) { \
+ } catch(const typename doctest::detail::remove_const< \
+ typename doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) { \
_DOCTEST_RB.translateException(); \
_DOCTEST_RB.m_threw_as = true; \
} catch(...) { _DOCTEST_RB.translateException(); } \
DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \
} \
- } while((void)0, 0)
+ } while(false)
-#define DOCTEST_ASSERT_THROWS_WITH(expr, assert_type, ...) \
+#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \
do { \
if(!doctest::getContextOptions()->no_throw) { \
doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \
- __LINE__, #expr, "", __VA_ARGS__); \
+ __LINE__, expr_str, "", __VA_ARGS__); \
try { \
DOCTEST_CAST_TO_VOID(expr) \
} catch(...) { _DOCTEST_RB.translateException(); } \
DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \
} \
- } while((void)0, 0)
+ } while(false)
-#define DOCTEST_ASSERT_NOTHROW(expr, assert_type) \
+#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \
do { \
doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \
- __LINE__, #expr); \
+ __LINE__, #__VA_ARGS__); \
try { \
- DOCTEST_CAST_TO_VOID(expr) \
+ DOCTEST_CAST_TO_VOID(__VA_ARGS__) \
} catch(...) { _DOCTEST_RB.translateException(); } \
DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \
- } while((void)0, 0)
+ } while(false)
// clang-format off
-#define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_WARN_THROWS, "")
-#define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_CHECK_THROWS, "")
-#define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS_WITH(expr, DT_REQUIRE_THROWS, "")
+#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "")
+#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "")
+#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "")
#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__)
#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__)
#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__)
-#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, DT_WARN_THROWS_WITH, __VA_ARGS__)
-#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, DT_CHECK_THROWS_WITH, __VA_ARGS__)
-#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__)
+#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__)
+#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__)
+#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__)
#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__)
#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__)
#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__)
-#define DOCTEST_WARN_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_WARN_NOTHROW)
-#define DOCTEST_CHECK_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_CHECK_NOTHROW)
-#define DOCTEST_REQUIRE_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_REQUIRE_NOTHROW)
+#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__)
+#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__)
+#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__)
-#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS(expr); } while((void)0, 0)
-#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS(expr); } while((void)0, 0)
-#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS(expr); } while((void)0, 0)
-#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_AS(expr, ex); } while((void)0, 0)
-#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_AS(expr, ex); } while((void)0, 0)
-#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while((void)0, 0)
-#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_WITH(expr, with); } while((void)0, 0)
-#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_WITH(expr, with); } while((void)0, 0)
-#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } while((void)0, 0)
-#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } while((void)0, 0)
-#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } while((void)0, 0)
-#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } while((void)0, 0)
-#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_NOTHROW(expr); } while((void)0, 0)
-#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_NOTHROW(expr); } while((void)0, 0)
-#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_NOTHROW(expr); } while((void)0, 0)
+#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); } while(false)
+#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); } while(false)
+#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); } while(false)
+#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); } while(false)
+#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); } while(false)
+#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while(false)
+#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); } while(false)
+#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); } while(false)
+#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } while(false)
+#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } while(false)
+#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } while(false)
+#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } while(false)
+#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); } while(false)
+#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); } while(false)
+#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); } while(false)
// clang-format on
#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS
@@ -2100,7 +2202,7 @@
_DOCTEST_RB.binary_assert<doctest::detail::binaryAssertComparison::comp>( \
__VA_ARGS__)) \
DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \
- } while((void)0, 0)
+ } while(false)
#define DOCTEST_UNARY_ASSERT(assert_type, ...) \
do { \
@@ -2108,7 +2210,7 @@
__LINE__, #__VA_ARGS__); \
DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(__VA_ARGS__)) \
DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \
- } while((void)0, 0)
+ } while(false)
#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS
@@ -2184,37 +2286,37 @@
#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS
-#define DOCTEST_WARN_THROWS(expr) ((void)0)
-#define DOCTEST_CHECK_THROWS(expr) ((void)0)
-#define DOCTEST_REQUIRE_THROWS(expr) ((void)0)
-#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0)
-#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ((void)0)
-#define DOCTEST_WARN_NOTHROW(expr) ((void)0)
-#define DOCTEST_CHECK_NOTHROW(expr) ((void)0)
-#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0)
+#define DOCTEST_WARN_THROWS(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS(...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_AS(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_AS(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_NOTHROW(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_NOTHROW(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_NOTHROW(...) (static_cast<void>(0))
-#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0)
-#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0)
+#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS
@@ -2305,86 +2407,86 @@
#define DOCTEST_REGISTER_REPORTER(name, priority, reporter)
#define DOCTEST_REGISTER_LISTENER(name, priority, reporter)
-#define DOCTEST_INFO(x) ((void)0)
-#define DOCTEST_CAPTURE(x) ((void)0)
-#define DOCTEST_ADD_MESSAGE_AT(file, line, x) ((void)0)
-#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) ((void)0)
-#define DOCTEST_ADD_FAIL_AT(file, line, x) ((void)0)
-#define DOCTEST_MESSAGE(x) ((void)0)
-#define DOCTEST_FAIL_CHECK(x) ((void)0)
-#define DOCTEST_FAIL(x) ((void)0)
+#define DOCTEST_INFO(...) (static_cast<void>(0))
+#define DOCTEST_CAPTURE(x) (static_cast<void>(0))
+#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast<void>(0))
+#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast<void>(0))
+#define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast<void>(0))
+#define DOCTEST_MESSAGE(...) (static_cast<void>(0))
+#define DOCTEST_FAIL_CHECK(...) (static_cast<void>(0))
+#define DOCTEST_FAIL(...) (static_cast<void>(0))
-#define DOCTEST_WARN(...) ((void)0)
-#define DOCTEST_CHECK(...) ((void)0)
-#define DOCTEST_REQUIRE(...) ((void)0)
-#define DOCTEST_WARN_FALSE(...) ((void)0)
-#define DOCTEST_CHECK_FALSE(...) ((void)0)
-#define DOCTEST_REQUIRE_FALSE(...) ((void)0)
+#define DOCTEST_WARN(...) (static_cast<void>(0))
+#define DOCTEST_CHECK(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE(...) (static_cast<void>(0))
+#define DOCTEST_WARN_FALSE(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_FALSE(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_FALSE(...) (static_cast<void>(0))
-#define DOCTEST_WARN_MESSAGE(cond, msg) ((void)0)
-#define DOCTEST_CHECK_MESSAGE(cond, msg) ((void)0)
-#define DOCTEST_REQUIRE_MESSAGE(cond, msg) ((void)0)
-#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) ((void)0)
-#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) ((void)0)
-#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) ((void)0)
+#define DOCTEST_WARN_MESSAGE(cond, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_MESSAGE(cond, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_MESSAGE(cond, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) (static_cast<void>(0))
-#define DOCTEST_WARN_THROWS(expr) ((void)0)
-#define DOCTEST_CHECK_THROWS(expr) ((void)0)
-#define DOCTEST_REQUIRE_THROWS(expr) ((void)0)
-#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0)
-#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ((void)0)
-#define DOCTEST_WARN_NOTHROW(expr) ((void)0)
-#define DOCTEST_CHECK_NOTHROW(expr) ((void)0)
-#define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0)
+#define DOCTEST_WARN_THROWS(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS(...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_AS(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_AS(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_NOTHROW(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_NOTHROW(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_NOTHROW(...) (static_cast<void>(0))
-#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0)
-#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0)
-#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0)
-#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0)
-#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0)
-#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0)
+#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast<void>(0))
+#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) (static_cast<void>(0))
-#define DOCTEST_WARN_EQ(...) ((void)0)
-#define DOCTEST_CHECK_EQ(...) ((void)0)
-#define DOCTEST_REQUIRE_EQ(...) ((void)0)
-#define DOCTEST_WARN_NE(...) ((void)0)
-#define DOCTEST_CHECK_NE(...) ((void)0)
-#define DOCTEST_REQUIRE_NE(...) ((void)0)
-#define DOCTEST_WARN_GT(...) ((void)0)
-#define DOCTEST_CHECK_GT(...) ((void)0)
-#define DOCTEST_REQUIRE_GT(...) ((void)0)
-#define DOCTEST_WARN_LT(...) ((void)0)
-#define DOCTEST_CHECK_LT(...) ((void)0)
-#define DOCTEST_REQUIRE_LT(...) ((void)0)
-#define DOCTEST_WARN_GE(...) ((void)0)
-#define DOCTEST_CHECK_GE(...) ((void)0)
-#define DOCTEST_REQUIRE_GE(...) ((void)0)
-#define DOCTEST_WARN_LE(...) ((void)0)
-#define DOCTEST_CHECK_LE(...) ((void)0)
-#define DOCTEST_REQUIRE_LE(...) ((void)0)
+#define DOCTEST_WARN_EQ(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_EQ(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_EQ(...) (static_cast<void>(0))
+#define DOCTEST_WARN_NE(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_NE(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_NE(...) (static_cast<void>(0))
+#define DOCTEST_WARN_GT(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_GT(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_GT(...) (static_cast<void>(0))
+#define DOCTEST_WARN_LT(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_LT(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_LT(...) (static_cast<void>(0))
+#define DOCTEST_WARN_GE(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_GE(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_GE(...) (static_cast<void>(0))
+#define DOCTEST_WARN_LE(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_LE(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_LE(...) (static_cast<void>(0))
-#define DOCTEST_WARN_UNARY(...) ((void)0)
-#define DOCTEST_CHECK_UNARY(...) ((void)0)
-#define DOCTEST_REQUIRE_UNARY(...) ((void)0)
-#define DOCTEST_WARN_UNARY_FALSE(...) ((void)0)
-#define DOCTEST_CHECK_UNARY_FALSE(...) ((void)0)
-#define DOCTEST_REQUIRE_UNARY_FALSE(...) ((void)0)
+#define DOCTEST_WARN_UNARY(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_UNARY(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_UNARY(...) (static_cast<void>(0))
+#define DOCTEST_WARN_UNARY_FALSE(...) (static_cast<void>(0))
+#define DOCTEST_CHECK_UNARY_FALSE(...) (static_cast<void>(0))
+#define DOCTEST_REQUIRE_UNARY_FALSE(...) (static_cast<void>(0))
#endif // DOCTEST_CONFIG_DISABLE
@@ -2416,7 +2518,7 @@
#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE
#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE
-#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INVOKE
+#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__)
// clang-format on
// BDD style macros
@@ -2436,138 +2538,138 @@
// == SHORT VERSIONS OF THE MACROS
#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES)
-#define TEST_CASE DOCTEST_TEST_CASE
-#define TEST_CASE_CLASS DOCTEST_TEST_CASE_CLASS
-#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE
-#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING
-#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE
-#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE
-#define TEST_CASE_TEMPLATE_INVOKE DOCTEST_TEST_CASE_TEMPLATE_INVOKE
-#define TEST_CASE_TEMPLATE_APPLY DOCTEST_TEST_CASE_TEMPLATE_APPLY
-#define SUBCASE DOCTEST_SUBCASE
-#define TEST_SUITE DOCTEST_TEST_SUITE
-#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN
+#define TEST_CASE(name) DOCTEST_TEST_CASE(name)
+#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name)
+#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name)
+#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__)
+#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__)
+#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id)
+#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__)
+#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__)
+#define SUBCASE(name) DOCTEST_SUBCASE(name)
+#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators)
+#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name)
#define TEST_SUITE_END DOCTEST_TEST_SUITE_END
-#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR
-#define REGISTER_REPORTER DOCTEST_REGISTER_REPORTER
-#define REGISTER_LISTENER DOCTEST_REGISTER_LISTENER
-#define INFO DOCTEST_INFO
-#define CAPTURE DOCTEST_CAPTURE
-#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT
-#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT
-#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT
-#define MESSAGE DOCTEST_MESSAGE
-#define FAIL_CHECK DOCTEST_FAIL_CHECK
-#define FAIL DOCTEST_FAIL
-#define TO_LVALUE DOCTEST_TO_LVALUE
+#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)
+#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter)
+#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter)
+#define INFO(...) DOCTEST_INFO(__VA_ARGS__)
+#define CAPTURE(x) DOCTEST_CAPTURE(x)
+#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__)
+#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__)
+#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__)
+#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__)
+#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__)
+#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__)
+#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__)
-#define WARN DOCTEST_WARN
-#define WARN_FALSE DOCTEST_WARN_FALSE
-#define WARN_THROWS DOCTEST_WARN_THROWS
-#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS
-#define WARN_THROWS_WITH DOCTEST_WARN_THROWS_WITH
-#define WARN_THROWS_WITH_AS DOCTEST_WARN_THROWS_WITH_AS
-#define WARN_NOTHROW DOCTEST_WARN_NOTHROW
-#define CHECK DOCTEST_CHECK
-#define CHECK_FALSE DOCTEST_CHECK_FALSE
-#define CHECK_THROWS DOCTEST_CHECK_THROWS
-#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS
-#define CHECK_THROWS_WITH DOCTEST_CHECK_THROWS_WITH
-#define CHECK_THROWS_WITH_AS DOCTEST_CHECK_THROWS_WITH_AS
-#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW
-#define REQUIRE DOCTEST_REQUIRE
-#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE
-#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS
-#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS
-#define REQUIRE_THROWS_WITH DOCTEST_REQUIRE_THROWS_WITH
-#define REQUIRE_THROWS_WITH_AS DOCTEST_REQUIRE_THROWS_WITH_AS
-#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW
+#define WARN(...) DOCTEST_WARN(__VA_ARGS__)
+#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__)
+#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__)
+#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__)
+#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__)
+#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__)
+#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__)
+#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__)
+#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__)
+#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__)
+#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__)
+#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__)
+#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__)
+#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__)
+#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__)
+#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__)
+#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__)
+#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__)
+#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__)
-#define WARN_MESSAGE DOCTEST_WARN_MESSAGE
-#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE
-#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE
-#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE
-#define WARN_THROWS_WITH_MESSAGE DOCTEST_WARN_THROWS_WITH_MESSAGE
-#define WARN_THROWS_WITH_AS_MESSAGE DOCTEST_WARN_THROWS_WITH_AS_MESSAGE
-#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE
-#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE
-#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE
-#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE
-#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE
-#define CHECK_THROWS_WITH_MESSAGE DOCTEST_CHECK_THROWS_WITH_MESSAGE
-#define CHECK_THROWS_WITH_AS_MESSAGE DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE
-#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE
-#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE
-#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE
-#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE
-#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE
-#define REQUIRE_THROWS_WITH_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_MESSAGE
-#define REQUIRE_THROWS_WITH_AS_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE
-#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE
+#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__)
+#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__)
+#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__)
+#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
+#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
+#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
+#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__)
+#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__)
+#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__)
+#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__)
+#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
+#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
+#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
+#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__)
+#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__)
+#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__)
+#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__)
+#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
+#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__)
-#define SCENARIO DOCTEST_SCENARIO
-#define SCENARIO_CLASS DOCTEST_SCENARIO_CLASS
-#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE
-#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE
-#define GIVEN DOCTEST_GIVEN
-#define WHEN DOCTEST_WHEN
-#define AND_WHEN DOCTEST_AND_WHEN
-#define THEN DOCTEST_THEN
-#define AND_THEN DOCTEST_AND_THEN
+#define SCENARIO(name) DOCTEST_SCENARIO(name)
+#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name)
+#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__)
+#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id)
+#define GIVEN(name) DOCTEST_GIVEN(name)
+#define WHEN(name) DOCTEST_WHEN(name)
+#define AND_WHEN(name) DOCTEST_AND_WHEN(name)
+#define THEN(name) DOCTEST_THEN(name)
+#define AND_THEN(name) DOCTEST_AND_THEN(name)
-#define WARN_EQ DOCTEST_WARN_EQ
-#define CHECK_EQ DOCTEST_CHECK_EQ
-#define REQUIRE_EQ DOCTEST_REQUIRE_EQ
-#define WARN_NE DOCTEST_WARN_NE
-#define CHECK_NE DOCTEST_CHECK_NE
-#define REQUIRE_NE DOCTEST_REQUIRE_NE
-#define WARN_GT DOCTEST_WARN_GT
-#define CHECK_GT DOCTEST_CHECK_GT
-#define REQUIRE_GT DOCTEST_REQUIRE_GT
-#define WARN_LT DOCTEST_WARN_LT
-#define CHECK_LT DOCTEST_CHECK_LT
-#define REQUIRE_LT DOCTEST_REQUIRE_LT
-#define WARN_GE DOCTEST_WARN_GE
-#define CHECK_GE DOCTEST_CHECK_GE
-#define REQUIRE_GE DOCTEST_REQUIRE_GE
-#define WARN_LE DOCTEST_WARN_LE
-#define CHECK_LE DOCTEST_CHECK_LE
-#define REQUIRE_LE DOCTEST_REQUIRE_LE
-#define WARN_UNARY DOCTEST_WARN_UNARY
-#define CHECK_UNARY DOCTEST_CHECK_UNARY
-#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY
-#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE
-#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE
-#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE
+#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__)
+#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__)
+#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__)
+#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__)
+#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__)
+#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__)
+#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__)
+#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__)
+#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__)
+#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__)
+#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__)
+#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__)
+#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__)
+#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__)
+#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__)
+#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__)
+#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__)
+#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__)
+#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__)
+#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__)
+#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__)
+#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__)
+#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__)
+#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
// KEPT FOR BACKWARDS COMPATIBILITY
-#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ
-#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ
-#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ
-#define FAST_WARN_NE DOCTEST_FAST_WARN_NE
-#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE
-#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE
-#define FAST_WARN_GT DOCTEST_FAST_WARN_GT
-#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT
-#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT
-#define FAST_WARN_LT DOCTEST_FAST_WARN_LT
-#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT
-#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT
-#define FAST_WARN_GE DOCTEST_FAST_WARN_GE
-#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE
-#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE
-#define FAST_WARN_LE DOCTEST_FAST_WARN_LE
-#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE
-#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE
+#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__)
+#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__)
+#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__)
+#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__)
+#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__)
+#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__)
+#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__)
+#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__)
+#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__)
+#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__)
+#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__)
+#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__)
+#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__)
+#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__)
+#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__)
+#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__)
+#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__)
+#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__)
-#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY
-#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY
-#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY
-#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE
-#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE
-#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE
+#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__)
+#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__)
+#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__)
+#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__)
+#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__)
+#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
-#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE
+#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__)
#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES
@@ -2644,6 +2746,7 @@
DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
+DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path")
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas")
@@ -2724,9 +2827,7 @@
#include <map>
#include <exception>
#include <stdexcept>
-#ifdef DOCTEST_CONFIG_POSIX_SIGNALS
#include <csignal>
-#endif // DOCTEST_CONFIG_POSIX_SIGNALS
#include <cfloat>
#include <cctype>
#include <cstdint>
@@ -2751,7 +2852,7 @@
#ifdef __AFXDLL
#include <AfxWin.h>
#else
-#include <Windows.h>
+#include <windows.h>
#endif
#include <io.h>
@@ -2762,6 +2863,12 @@
#endif // DOCTEST_PLATFORM_WINDOWS
+// this is a fix for https://github.com/onqtam/doctest/issues/348
+// https://mail.gnome.org/archives/xml/2012-January/msg00000.html
+#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO)
+#define STDOUT_FILENO fileno(stdout)
+#endif // HAVE_UNISTD_H
+
DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
// counts the number of elements in a C array
@@ -2781,12 +2888,24 @@
#define DOCTEST_THREAD_LOCAL thread_local
#endif
+#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES
+#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32
+#endif
+
+#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE
+#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64
+#endif
+
#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX
#else
#define DOCTEST_OPTIONS_PREFIX_DISPLAY ""
#endif
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
+#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+#endif
+
namespace doctest {
bool is_running_in_test = false;
@@ -2913,24 +3032,111 @@
//unsigned int getElapsedMilliseconds() const {
// return static_cast<unsigned int>(getElapsedMicroseconds() / 1000);
//}
- double getElapsedSeconds() const { return (getCurrentTicks() - m_ticks) / 1000000.0; }
+ double getElapsedSeconds() const { return static_cast<double>(getCurrentTicks() - m_ticks) / 1000000.0; }
private:
ticks_t m_ticks = 0;
};
+#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+ template <typename T>
+ using AtomicOrMultiLaneAtomic = std::atomic<T>;
+#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+ // Provides a multilane implementation of an atomic variable that supports add, sub, load,
+ // store. Instead of using a single atomic variable, this splits up into multiple ones,
+ // each sitting on a separate cache line. The goal is to provide a speedup when most
+ // operations are modifying. It achieves this with two properties:
+ //
+ // * Multiple atomics are used, so chance of congestion from the same atomic is reduced.
+ // * Each atomic sits on a separate cache line, so false sharing is reduced.
+ //
+ // The disadvantage is that there is a small overhead due to the use of TLS, and load/store
+ // is slower because all atomics have to be accessed.
+ template <typename T>
+ class MultiLaneAtomic
+ {
+ struct CacheLineAlignedAtomic
+ {
+ std::atomic<T> atomic{};
+ char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];
+ };
+ CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];
+
+ static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE,
+ "guarantee one atomic takes exactly one cache line");
+
+ public:
+ T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; }
+
+ T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); }
+
+ T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
+ return myAtomic().fetch_add(arg, order);
+ }
+
+ T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
+ return myAtomic().fetch_sub(arg, order);
+ }
+
+ operator T() const DOCTEST_NOEXCEPT { return load(); }
+
+ T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT {
+ auto result = T();
+ for(auto const& c : m_atomics) {
+ result += c.atomic.load(order);
+ }
+ return result;
+ }
+
+ T operator=(T desired) DOCTEST_NOEXCEPT {
+ store(desired);
+ return desired;
+ }
+
+ void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
+ // first value becomes desired", all others become 0.
+ for(auto& c : m_atomics) {
+ c.atomic.store(desired, order);
+ desired = {};
+ }
+ }
+
+ private:
+ // Each thread has a different atomic that it operates on. If more than NumLanes threads
+ // use this, some will use the same atomic. So performance will degrate a bit, but still
+ // everything will work.
+ //
+ // The logic here is a bit tricky. The call should be as fast as possible, so that there
+ // is minimal to no overhead in determining the correct atomic for the current thread.
+ //
+ // 1. A global static counter laneCounter counts continuously up.
+ // 2. Each successive thread will use modulo operation of that counter so it gets an atomic
+ // assigned in a round-robin fashion.
+ // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with
+ // little overhead.
+ std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
+ static std::atomic<size_t> laneCounter;
+ DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =
+ laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;
+
+ return m_atomics[tlsLaneIdx].atomic;
+ }
+ };
+
+ template <typename T>
+ using AtomicOrMultiLaneAtomic = MultiLaneAtomic<T>;
+#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+
// this holds both parameters from the command line and runtime data for tests
struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats
{
- std::atomic<int> numAssertsCurrentTest_atomic;
- std::atomic<int> numAssertsFailedCurrentTest_atomic;
+ AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;
+ AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters
std::vector<IReporter*> reporters_currently_used;
- const TestCase* currentTest = nullptr;
-
assert_handler ah = nullptr;
Timer timer;
@@ -3031,6 +3237,7 @@
String::~String() {
if(!isOnStack())
delete[] data.ptr;
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
}
String::String(const char* in)
@@ -3039,14 +3246,16 @@
String::String(const char* in, unsigned in_size) {
using namespace std;
if(in_size <= last) {
- memcpy(buf, in, in_size + 1);
+ memcpy(buf, in, in_size);
+ buf[in_size] = '\0';
setLast(last - in_size);
} else {
setOnHeap();
data.size = in_size;
data.capacity = data.size + 1;
data.ptr = new char[data.capacity];
- memcpy(data.ptr, in, in_size + 1);
+ memcpy(data.ptr, in, in_size);
+ data.ptr[in_size] = '\0';
}
}
@@ -3072,6 +3281,7 @@
if(total_size < len) {
// append to the current stack space
memcpy(buf + my_old_size, other.c_str(), other_size + 1);
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
setLast(last - total_size);
} else {
// alloc new chunk
@@ -3113,6 +3323,7 @@
return *this;
}
+// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
String String::operator+(const String& other) const { return String(*this) += other; }
String::String(String&& other) {
@@ -3267,6 +3478,7 @@
DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference")
// depending on the current options this will remove the path of filenames
const char* skipPathFromFilename(const char* file) {
+#ifndef DOCTEST_CONFIG_DISABLE
if(getContextOptions()->no_path_in_filenames) {
auto back = std::strrchr(file, '\\');
auto forward = std::strrchr(file, '/');
@@ -3276,6 +3488,7 @@
return forward + 1;
}
}
+#endif // DOCTEST_CONFIG_DISABLE
return file;
}
DOCTEST_CLANG_SUPPRESS_WARNING_POP
@@ -3294,6 +3507,7 @@
#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
String toString(char* in) { return toString(static_cast<const char*>(in)); }
+// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; }
#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING
String toString(bool in) { return in ? "true" : "false"; }
@@ -3366,6 +3580,7 @@
bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; }
String toString(const Approx& in) {
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
return String("Approx( ") + doctest::toString(in.m_value) + " )";
}
const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); }
@@ -3411,7 +3626,7 @@
namespace doctest_detail_test_suite_ns {
// holds the current test suite
doctest::detail::TestSuite& getCurrentTestSuite() {
- static doctest::detail::TestSuite data;
+ static doctest::detail::TestSuite data{};
return data;
}
} // namespace doctest_detail_test_suite_ns
@@ -3450,7 +3665,7 @@
}
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
- [[noreturn]] void throwException() {
+ DOCTEST_NORETURN void throwException() {
g_cs->shouldLogCurrentException = false;
throw TestFailureException();
} // NOLINT(cert-err60-cpp)
@@ -3464,8 +3679,8 @@
// matching of a string against a wildcard mask (case sensitivity configurable) taken from
// https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
int wildcmp(const char* str, const char* wild, bool caseSensitive) {
- const char* cp = nullptr;
- const char* mp = nullptr;
+ const char* cp = str;
+ const char* mp = wild;
while((*str) && (*wild != '*')) {
if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) &&
@@ -3523,7 +3738,7 @@
Subcase::Subcase(const String& name, const char* file, int line)
: m_signature({name, file, line}) {
- ContextState* s = g_cs;
+ auto* s = g_cs;
// check subcase filters
if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) {
@@ -3565,7 +3780,7 @@
g_cs->subcasesPassed.insert(g_cs->subcasesStack);
g_cs->subcasesStack.pop_back();
-#if __cplusplus >= 201703L && defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411
+#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
if(std::uncaught_exceptions() > 0
#else
if(std::uncaught_exception()
@@ -3600,6 +3815,8 @@
// clear state
m_description = nullptr;
m_skip = false;
+ m_no_breaks = false;
+ m_no_output = false;
m_may_fail = false;
m_should_fail = false;
m_expected_failures = 0;
@@ -3615,6 +3832,8 @@
m_test_suite = test_suite.m_test_suite;
m_description = test_suite.m_description;
m_skip = test_suite.m_skip;
+ m_no_breaks = test_suite.m_no_breaks;
+ m_no_output = test_suite.m_no_output;
m_may_fail = test_suite.m_may_fail;
m_should_fail = test_suite.m_should_fail;
m_expected_failures = test_suite.m_expected_failures;
@@ -3658,25 +3877,31 @@
}
bool TestCase::operator<(const TestCase& other) const {
+ // this will be used only to differentiate between test cases - not relevant for sorting
if(m_line != other.m_line)
return m_line < other.m_line;
- const int file_cmp = std::strcmp(m_file, other.m_file);
+ const int name_cmp = strcmp(m_name, other.m_name);
+ if(name_cmp != 0)
+ return name_cmp < 0;
+ const int file_cmp = m_file.compare(other.m_file);
if(file_cmp != 0)
return file_cmp < 0;
return m_template_id < other.m_template_id;
}
+
+ // all the registered tests
+ std::set<TestCase>& getRegisteredTests() {
+ static std::set<TestCase> data;
+ return data;
+ }
} // namespace detail
namespace {
using namespace detail;
// for sorting tests by file/line
bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) {
-#if DOCTEST_MSVC
// this is needed because MSVC gives different case for drive letters
// for __FILE__ when evaluated in a header and a source file
- const int res = doctest::stricmp(lhs->m_file, rhs->m_file);
-#else // MSVC
- const int res = std::strcmp(lhs->m_file, rhs->m_file);
-#endif // MSVC
+ const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC));
if(res != 0)
return res < 0;
if(lhs->m_line != rhs->m_line)
@@ -3700,12 +3925,6 @@
return suiteOrderComparator(lhs, rhs);
}
- // all the registered tests
- std::set<TestCase>& getRegisteredTests() {
- static std::set<TestCase> data;
- return data;
- }
-
#ifdef DOCTEST_CONFIG_COLORS_WINDOWS
HANDLE g_stdoutHandle;
WORD g_origFgAttrs;
@@ -3731,8 +3950,8 @@
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations")
void color_to_stream(std::ostream& s, Color::Enum code) {
- ((void)s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS
- ((void)code); // for DOCTEST_CONFIG_COLORS_NONE
+ static_cast<void>(s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS
+ static_cast<void>(code); // for DOCTEST_CONFIG_COLORS_NONE
#ifdef DOCTEST_CONFIG_COLORS_ANSI
if(g_no_colors ||
(isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false))
@@ -3838,7 +4057,28 @@
#ifdef DOCTEST_IS_DEBUGGER_ACTIVE
bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); }
#else // DOCTEST_IS_DEBUGGER_ACTIVE
-#ifdef DOCTEST_PLATFORM_MAC
+#ifdef DOCTEST_PLATFORM_LINUX
+ class ErrnoGuard {
+ public:
+ ErrnoGuard() : m_oldErrno(errno) {}
+ ~ErrnoGuard() { errno = m_oldErrno; }
+ private:
+ int m_oldErrno;
+ };
+ // See the comments in Catch2 for the reasoning behind this implementation:
+ // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102
+ bool isDebuggerActive() {
+ ErrnoGuard guard;
+ std::ifstream in("/proc/self/status");
+ for(std::string line; std::getline(in, line);) {
+ static const int PREFIX_LEN = 11;
+ if(line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) {
+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
+ }
+ }
+ return false;
+ }
+#elif defined(DOCTEST_PLATFORM_MAC)
// The following function is taken directly from the following technical note:
// https://developer.apple.com/library/archive/qa/qa1361/_index.html
// Returns true if the current process is being debugged (either
@@ -3865,7 +4105,7 @@
// We're being debugged if the P_TRACED flag is set.
return ((info.kp_proc.p_flag & P_TRACED) != 0);
}
-#elif DOCTEST_MSVC || defined(__MINGW32__)
+#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__)
bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; }
#else
bool isDebuggerActive() { return false; }
@@ -3913,7 +4153,7 @@
// ContextScope has been destroyed (base class destructors run after derived class destructors).
// Instead, ContextScope calls this method directly from its destructor.
void ContextScopeBase::destroy() {
-#if __cplusplus >= 201703L && defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411
+#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
if(std::uncaught_exceptions() > 0) {
#else
if(std::uncaught_exception()) {
@@ -3932,19 +4172,12 @@
namespace {
using namespace detail;
- std::ostream& file_line_to_stream(std::ostream& s, const char* file, int line,
- const char* tail = "") {
- const auto opt = getContextOptions();
- s << Color::LightGrey << skipPathFromFilename(file) << (opt->gnu_file_line ? ":" : "(")
- << (opt->no_line_numbers ? 0 : line) // 0 or the real num depending on the option
- << (opt->gnu_file_line ? ":" : "):") << tail;
- return s;
- }
-
#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH)
struct FatalConditionHandler
{
- void reset() {}
+ static void reset() {}
+ static void allocateAltStackMem() {}
+ static void freeAltStackMem() {}
};
#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
@@ -3961,26 +4194,45 @@
// Windows can easily distinguish between SO and SigSegV,
// but SigInt, SigTerm, etc are handled differently.
SignalDefs signalDefs[] = {
- {EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal"},
- {EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow"},
- {EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal"},
- {EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error"},
+ {static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION),
+ "SIGILL - Illegal instruction signal"},
+ {static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"},
+ {static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION),
+ "SIGSEGV - Segmentation violation signal"},
+ {static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"},
};
struct FatalConditionHandler
{
static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) {
- for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
- if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
- reportFatal(signalDefs[i].name);
- break;
+ // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the
+ // console just once no matter how many threads have crashed.
+ static std::mutex mutex;
+ static bool execute = true;
+ {
+ std::lock_guard<std::mutex> lock(mutex);
+ if(execute) {
+ bool reported = false;
+ for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) {
+ if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
+ reportFatal(signalDefs[i].name);
+ reported = true;
+ break;
+ }
+ }
+ if(reported == false)
+ reportFatal("Unhandled SEH exception caught");
+ if(isDebuggerActive() && !g_cs->no_breaks)
+ DOCTEST_BREAK_INTO_DEBUGGER();
}
+ execute = false;
}
- // If its not an exception we care about, pass it along.
- // This stops us from eating debugger breaks etc.
- return EXCEPTION_CONTINUE_SEARCH;
+ std::exit(EXIT_FAILURE);
}
+ static void allocateAltStackMem() {}
+ static void freeAltStackMem() {}
+
FatalConditionHandler() {
isSet = true;
// 32k seems enough for doctest to handle stack overflow,
@@ -3990,6 +4242,51 @@
previousTop = SetUnhandledExceptionFilter(handleException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
+
+ // On Windows uncaught exceptions from another thread, exceptions from
+ // destructors, or calls to std::terminate are not a SEH exception
+
+ // The terminal handler gets called when:
+ // - std::terminate is called FROM THE TEST RUNNER THREAD
+ // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD
+ original_terminate_handler = std::get_terminate();
+ std::set_terminate([]() DOCTEST_NOEXCEPT {
+ reportFatal("Terminate handler called");
+ if(isDebuggerActive() && !g_cs->no_breaks)
+ DOCTEST_BREAK_INTO_DEBUGGER();
+ std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well
+ });
+
+ // SIGABRT is raised when:
+ // - std::terminate is called FROM A DIFFERENT THREAD
+ // - an exception is thrown from a destructor FROM A DIFFERENT THREAD
+ // - an uncaught exception is thrown FROM A DIFFERENT THREAD
+ prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT {
+ if(signal == SIGABRT) {
+ reportFatal("SIGABRT - Abort (abnormal termination) signal");
+ if(isDebuggerActive() && !g_cs->no_breaks)
+ DOCTEST_BREAK_INTO_DEBUGGER();
+ std::exit(EXIT_FAILURE);
+ }
+ });
+
+ // The following settings are taken from google test, and more
+ // specifically from UnitTest::Run() inside of gtest.cc
+
+ // the user does not want to see pop-up dialogs about crashes
+ prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+ // This forces the abort message to go to stderr in all circumstances.
+ prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR);
+ // In the debug version, Visual Studio pops up a separate dialog
+ // offering a choice to debug the aborted program - we want to disable that.
+ prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+ // In debug mode, the Windows CRT can crash with an assertion over invalid
+ // input (e.g. passing an invalid file descriptor). The default handling
+ // for these assertions is to pop up a dialog and wait for user input.
+ // Instead ask the CRT to dump such assertions to stderr non-interactively.
+ prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
}
static void reset() {
@@ -3997,7 +4294,13 @@
// Unregister handler and restore the old guarantee
SetUnhandledExceptionFilter(previousTop);
SetThreadStackGuarantee(&guaranteeSize);
- previousTop = nullptr;
+ std::set_terminate(original_terminate_handler);
+ std::signal(SIGABRT, prev_sigabrt_handler);
+ SetErrorMode(prev_error_mode_1);
+ _set_error_mode(prev_error_mode_2);
+ _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+ static_cast<void>(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode));
+ static_cast<void>(_CrtSetReportFile(_CRT_ASSERT, prev_report_file));
isSet = false;
}
}
@@ -4005,11 +4308,25 @@
~FatalConditionHandler() { reset(); }
private:
+ static UINT prev_error_mode_1;
+ static int prev_error_mode_2;
+ static unsigned int prev_abort_behavior;
+ static int prev_report_mode;
+ static _HFILE prev_report_file;
+ static void (*prev_sigabrt_handler)(int);
+ static std::terminate_handler original_terminate_handler;
static bool isSet;
static ULONG guaranteeSize;
static LPTOP_LEVEL_EXCEPTION_FILTER previousTop;
};
+ UINT FatalConditionHandler::prev_error_mode_1;
+ int FatalConditionHandler::prev_error_mode_2;
+ unsigned int FatalConditionHandler::prev_abort_behavior;
+ int FatalConditionHandler::prev_report_mode;
+ _HFILE FatalConditionHandler::prev_report_file;
+ void (*FatalConditionHandler::prev_sigabrt_handler)(int);
+ std::terminate_handler FatalConditionHandler::original_terminate_handler;
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr;
@@ -4033,7 +4350,8 @@
static bool isSet;
static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)];
static stack_t oldSigStack;
- static char altStackMem[4 * SIGSTKSZ];
+ static size_t altStackSize;
+ static char* altStackMem;
static void handleSignal(int sig) {
const char* name = "<unknown signal>";
@@ -4049,11 +4367,19 @@
raise(sig);
}
+ static void allocateAltStackMem() {
+ altStackMem = new char[altStackSize];
+ }
+
+ static void freeAltStackMem() {
+ delete[] altStackMem;
+ }
+
FatalConditionHandler() {
isSet = true;
stack_t sigStack;
sigStack.ss_sp = altStackMem;
- sigStack.ss_size = sizeof(altStackMem);
+ sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = {};
@@ -4078,10 +4404,11 @@
}
};
- bool FatalConditionHandler::isSet = false;
+ bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {};
- stack_t FatalConditionHandler::oldSigStack = {};
- char FatalConditionHandler::altStackMem[] = {};
+ stack_t FatalConditionHandler::oldSigStack = {};
+ size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ;
+ char* FatalConditionHandler::altStackMem = nullptr;
#endif // DOCTEST_PLATFORM_WINDOWS
#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
@@ -4183,8 +4510,8 @@
failed_out_of_a_testing_context(*this);
}
- return m_failed && isDebuggerActive() &&
- !getContextOptions()->no_breaks; // break into debugger
+ return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks &&
+ (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
}
void ResultBuilder::react() const {
@@ -4209,6 +4536,7 @@
// ###################################################################################
DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp);
DOCTEST_ASSERT_IN_TESTS(result.m_decomp);
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
}
MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) {
@@ -4233,7 +4561,8 @@
addFailedAssert(m_severity);
}
- return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn; // break
+ return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn &&
+ (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
}
void MessageBuilder::react() {
@@ -4247,7 +4576,7 @@
using namespace detail;
template <typename Ex>
- [[noreturn]] void throw_exception(Ex const& e) {
+ DOCTEST_NORETURN void throw_exception(Ex const& e) {
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
throw e;
#else // DOCTEST_CONFIG_NO_EXCEPTIONS
@@ -4257,9 +4586,11 @@
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
}
+#ifndef DOCTEST_INTERNAL_ERROR
#define DOCTEST_INTERNAL_ERROR(msg) \
throw_exception(std::logic_error( \
__FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg))
+#endif // DOCTEST_INTERNAL_ERROR
// clang-format off
@@ -4290,8 +4621,8 @@
public:
ScopedElement( XmlWriter* writer );
- ScopedElement( ScopedElement&& other ) noexcept;
- ScopedElement& operator=( ScopedElement&& other ) noexcept;
+ ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT;
+ ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT;
~ScopedElement();
@@ -4508,11 +4839,11 @@
: m_writer( writer )
{}
- XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
+ XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT
: m_writer( other.m_writer ){
other.m_writer = nullptr;
}
- XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT {
if ( m_writer ) {
m_writer->endElement();
}
@@ -4691,7 +5022,7 @@
tc = ∈
xml.startElement("TestCase")
.writeAttribute("name", in.m_name)
- .writeAttribute("filename", skipPathFromFilename(in.m_file))
+ .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str()))
.writeAttribute("line", line(in.m_line))
.writeAttribute("description", in.m_description);
@@ -4722,7 +5053,7 @@
for(unsigned i = 0; i < in.num_data; ++i) {
xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name)
.writeAttribute("testsuite", in.data[i]->m_test_suite)
- .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file))
+ .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str()))
.writeAttribute("line", line(in.data[i]->m_line));
}
xml.scopedElement("OverallResultsTestCases")
@@ -4878,6 +5209,279 @@
DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter);
+ void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) {
+ if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) ==
+ 0) //!OCLINT bitwise operator in conditional
+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) "
+ << Color::None;
+
+ if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional
+ s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n";
+ } else if((rb.m_at & assertType::is_throws_as) &&
+ (rb.m_at & assertType::is_throws_with)) { //!OCLINT
+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
+ << rb.m_exception_string << "\", " << rb.m_exception_type << " ) " << Color::None;
+ if(rb.m_threw) {
+ if(!rb.m_failed) {
+ s << "threw as expected!\n";
+ } else {
+ s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n";
+ }
+ } else {
+ s << "did NOT throw at all!\n";
+ }
+ } else if(rb.m_at &
+ assertType::is_throws_as) { //!OCLINT bitwise operator in conditional
+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", "
+ << rb.m_exception_type << " ) " << Color::None
+ << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" :
+ "threw a DIFFERENT exception: ") :
+ "did NOT throw at all!")
+ << Color::Cyan << rb.m_exception << "\n";
+ } else if(rb.m_at &
+ assertType::is_throws_with) { //!OCLINT bitwise operator in conditional
+ s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
+ << rb.m_exception_string << "\" ) " << Color::None
+ << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" :
+ "threw a DIFFERENT exception: ") :
+ "did NOT throw at all!")
+ << Color::Cyan << rb.m_exception << "\n";
+ } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional
+ s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan
+ << rb.m_exception << "\n";
+ } else {
+ s << (rb.m_threw ? "THREW exception: " :
+ (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n"));
+ if(rb.m_threw)
+ s << rb.m_exception << "\n";
+ else
+ s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n";
+ }
+ }
+
+ // TODO:
+ // - log_message()
+ // - respond to queries
+ // - honor remaining options
+ // - more attributes in tags
+ struct JUnitReporter : public IReporter
+ {
+ XmlWriter xml;
+ std::mutex mutex;
+ Timer timer;
+ std::vector<String> deepestSubcaseStackNames;
+
+ struct JUnitTestCaseData
+ {
+ static std::string getCurrentTimestamp() {
+ // Beware, this is not reentrant because of backward compatibility issues
+ // Also, UTC only, again because of backward compatibility (%z is C++11)
+ time_t rawtime;
+ std::time(&rawtime);
+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
+
+ std::tm timeInfo;
+#ifdef DOCTEST_PLATFORM_WINDOWS
+ gmtime_s(&timeInfo, &rawtime);
+#else // DOCTEST_PLATFORM_WINDOWS
+ gmtime_r(&rawtime, &timeInfo);
+#endif // DOCTEST_PLATFORM_WINDOWS
+
+ char timeStamp[timeStampSize];
+ const char* const fmt = "%Y-%m-%dT%H:%M:%SZ";
+
+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
+ return std::string(timeStamp);
+ }
+
+ struct JUnitTestMessage
+ {
+ JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details)
+ : message(_message), type(_type), details(_details) {}
+
+ JUnitTestMessage(const std::string& _message, const std::string& _details)
+ : message(_message), type(), details(_details) {}
+
+ std::string message, type, details;
+ };
+
+ struct JUnitTestCase
+ {
+ JUnitTestCase(const std::string& _classname, const std::string& _name)
+ : classname(_classname), name(_name), time(0), failures() {}
+
+ std::string classname, name;
+ double time;
+ std::vector<JUnitTestMessage> failures, errors;
+ };
+
+ void add(const std::string& classname, const std::string& name) {
+ testcases.emplace_back(classname, name);
+ }
+
+ void appendSubcaseNamesToLastTestcase(std::vector<String> nameStack) {
+ for(auto& curr: nameStack)
+ if(curr.size())
+ testcases.back().name += std::string("/") + curr.c_str();
+ }
+
+ void addTime(double time) {
+ if(time < 1e-4)
+ time = 0;
+ testcases.back().time = time;
+ totalSeconds += time;
+ }
+
+ void addFailure(const std::string& message, const std::string& type, const std::string& details) {
+ testcases.back().failures.emplace_back(message, type, details);
+ ++totalFailures;
+ }
+
+ void addError(const std::string& message, const std::string& details) {
+ testcases.back().errors.emplace_back(message, details);
+ ++totalErrors;
+ }
+
+ std::vector<JUnitTestCase> testcases;
+ double totalSeconds = 0;
+ int totalErrors = 0, totalFailures = 0;
+ };
+
+ JUnitTestCaseData testCaseData;
+
+ // caching pointers/references to objects of these types - safe to do
+ const ContextOptions& opt;
+ const TestCaseData* tc = nullptr;
+
+ JUnitReporter(const ContextOptions& co)
+ : xml(*co.cout)
+ , opt(co) {}
+
+ unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; }
+
+ // =========================================================================================
+ // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE
+ // =========================================================================================
+
+ void report_query(const QueryData&) override {}
+
+ void test_run_start() override {}
+
+ void test_run_end(const TestRunStats& p) override {
+ // remove .exe extension - mainly to have the same output on UNIX and Windows
+ std::string binary_name = skipPathFromFilename(opt.binary_name.c_str());
+#ifdef DOCTEST_PLATFORM_WINDOWS
+ if(binary_name.rfind(".exe") != std::string::npos)
+ binary_name = binary_name.substr(0, binary_name.length() - 4);
+#endif // DOCTEST_PLATFORM_WINDOWS
+ xml.startElement("testsuites");
+ xml.startElement("testsuite").writeAttribute("name", binary_name)
+ .writeAttribute("errors", testCaseData.totalErrors)
+ .writeAttribute("failures", testCaseData.totalFailures)
+ .writeAttribute("tests", p.numAsserts);
+ if(opt.no_time_in_output == false) {
+ xml.writeAttribute("time", testCaseData.totalSeconds);
+ xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp());
+ }
+ if(opt.no_version == false)
+ xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR);
+
+ for(const auto& testCase : testCaseData.testcases) {
+ xml.startElement("testcase")
+ .writeAttribute("classname", testCase.classname)
+ .writeAttribute("name", testCase.name);
+ if(opt.no_time_in_output == false)
+ xml.writeAttribute("time", testCase.time);
+ // This is not ideal, but it should be enough to mimic gtest's junit output.
+ xml.writeAttribute("status", "run");
+
+ for(const auto& failure : testCase.failures) {
+ xml.scopedElement("failure")
+ .writeAttribute("message", failure.message)
+ .writeAttribute("type", failure.type)
+ .writeText(failure.details, false);
+ }
+
+ for(const auto& error : testCase.errors) {
+ xml.scopedElement("error")
+ .writeAttribute("message", error.message)
+ .writeText(error.details);
+ }
+
+ xml.endElement();
+ }
+ xml.endElement();
+ xml.endElement();
+ }
+
+ void test_case_start(const TestCaseData& in) override {
+ testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);
+ timer.start();
+ }
+
+ void test_case_reenter(const TestCaseData& in) override {
+ testCaseData.addTime(timer.getElapsedSeconds());
+ testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);
+ deepestSubcaseStackNames.clear();
+
+ timer.start();
+ testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name);
+ }
+
+ void test_case_end(const CurrentTestCaseStats&) override {
+ testCaseData.addTime(timer.getElapsedSeconds());
+ testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames);
+ deepestSubcaseStackNames.clear();
+ }
+
+ void test_case_exception(const TestCaseException& e) override {
+ std::lock_guard<std::mutex> lock(mutex);
+ testCaseData.addError("exception", e.error_string.c_str());
+ }
+
+ void subcase_start(const SubcaseSignature& in) override {
+ std::lock_guard<std::mutex> lock(mutex);
+ deepestSubcaseStackNames.push_back(in.m_name);
+ }
+
+ void subcase_end() override {}
+
+ void log_assert(const AssertData& rb) override {
+ if(!rb.m_failed) // report only failures & ignore the `success` option
+ return;
+
+ std::lock_guard<std::mutex> lock(mutex);
+
+ std::ostringstream os;
+ os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(")
+ << line(rb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl;
+
+ fulltext_log_assert_to_stream(os, rb);
+ log_contexts(os);
+ testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str());
+ }
+
+ void log_message(const MessageData&) override {}
+
+ void test_case_skipped(const TestCaseData&) override {}
+
+ void log_contexts(std::ostringstream& s) {
+ int num_contexts = get_num_active_contexts();
+ if(num_contexts) {
+ auto contexts = get_active_contexts();
+
+ s << " logged: ";
+ for(int i = 0; i < num_contexts; ++i) {
+ s << (i == 0 ? "" : " ");
+ contexts[i]->stringify(&s);
+ s << std::endl;
+ }
+ }
+ }
+ };
+
+ DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter);
+
struct Whitespace
{
int nrSpaces;
@@ -4896,6 +5500,7 @@
std::ostream& s;
bool hasLoggedCurrentTestStart;
std::vector<SubcaseSignature> subcasesStack;
+ size_t currentSubcaseLevel;
std::mutex mutex;
// caching pointers/references to objects of these types - safe to do
@@ -4954,23 +5559,40 @@
s << "\n";
}
+ // this was requested to be made virtual so users could override it
+ virtual void file_line_to_stream(const char* file, int line,
+ const char* tail = "") {
+ s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(")
+ << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option
+ << (opt.gnu_file_line ? ":" : "):") << tail;
+ }
+
void logTestStart() {
if(hasLoggedCurrentTestStart)
return;
separator_to_stream();
- file_line_to_stream(s, tc->m_file, tc->m_line, "\n");
+ file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n");
if(tc->m_description)
s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n";
if(tc->m_test_suite && tc->m_test_suite[0] != '\0')
s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n";
if(strncmp(tc->m_name, " Scenario:", 11) != 0)
- s << Color::None << "TEST CASE: ";
+ s << Color::Yellow << "TEST CASE: ";
s << Color::None << tc->m_name << "\n";
- for(auto& curr : subcasesStack)
- if(curr.m_name[0] != '\0')
- s << " " << curr.m_name << "\n";
+ for(size_t i = 0; i < currentSubcaseLevel; ++i) {
+ if(subcasesStack[i].m_name[0] != '\0')
+ s << " " << subcasesStack[i].m_name << "\n";
+ }
+
+ if(currentSubcaseLevel != subcasesStack.size()) {
+ s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None;
+ for(size_t i = 0; i < subcasesStack.size(); ++i) {
+ if(subcasesStack[i].m_name[0] != '\0')
+ s << " " << subcasesStack[i].m_name << "\n";
+ }
+ }
s << "\n";
@@ -5048,7 +5670,7 @@
<< Whitespace(sizePrefixDisplay*1) << "output filename\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by=<string> "
<< Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n";
- s << Whitespace(sizePrefixDisplay*3) << " <string> - by [file/suite/name/rand]\n";
+ s << Whitespace(sizePrefixDisplay*3) << " <string> - [file/suite/name/rand/none]\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed=<int> "
<< Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first=<int> "
@@ -5181,25 +5803,28 @@
separator_to_stream();
s << std::dec;
+ auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast<unsigned>(p.numAsserts))) + 1)));
+ auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast<unsigned>(p.numAsserts - p.numAssertsFailed))) + 1)));
+ auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast<unsigned>(p.numAssertsFailed))) + 1)));
const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0;
- s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(6)
+ s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth)
<< p.numTestCasesPassingFilters << " | "
<< ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None :
Color::Green)
- << std::setw(6) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed"
+ << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed"
<< Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None)
- << std::setw(6) << p.numTestCasesFailed << " failed" << Color::None << " | ";
+ << std::setw(failwidth) << p.numTestCasesFailed << " failed" << Color::None << " |";
if(opt.no_skipped_summary == false) {
const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters;
- s << (numSkipped == 0 ? Color::None : Color::Yellow) << std::setw(6) << numSkipped
+ s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped
<< " skipped" << Color::None;
}
s << "\n";
- s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(6)
+ s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth)
<< p.numAsserts << " | "
<< ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green)
- << std::setw(6) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None
- << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(6)
+ << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None
+ << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth)
<< p.numAssertsFailed << " failed" << Color::None << " |\n";
s << Color::Cyan << "[doctest] " << Color::None
<< "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green)
@@ -5209,11 +5834,18 @@
void test_case_start(const TestCaseData& in) override {
hasLoggedCurrentTestStart = false;
tc = ∈
+ subcasesStack.clear();
+ currentSubcaseLevel = 0;
}
- void test_case_reenter(const TestCaseData&) override {}
+ void test_case_reenter(const TestCaseData&) override {
+ subcasesStack.clear();
+ }
void test_case_end(const CurrentTestCaseStats& st) override {
+ if(tc->m_no_output)
+ return;
+
// log the preamble of the test case only if there is something
// else to print - something other than that an assert has failed
if(opt.duration ||
@@ -5248,9 +5880,12 @@
}
void test_case_exception(const TestCaseException& e) override {
+ if(tc->m_no_output)
+ return;
+
logTestStart();
- file_line_to_stream(s, tc->m_file, tc->m_line, " ");
+ file_line_to_stream(tc->m_file.c_str(), tc->m_line, " ");
successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require :
assertType::is_check);
s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ")
@@ -5271,82 +5906,41 @@
void subcase_start(const SubcaseSignature& subc) override {
std::lock_guard<std::mutex> lock(mutex);
subcasesStack.push_back(subc);
+ ++currentSubcaseLevel;
hasLoggedCurrentTestStart = false;
}
void subcase_end() override {
std::lock_guard<std::mutex> lock(mutex);
- subcasesStack.pop_back();
+ --currentSubcaseLevel;
hasLoggedCurrentTestStart = false;
}
void log_assert(const AssertData& rb) override {
- if(!rb.m_failed && !opt.success)
+ if((!rb.m_failed && !opt.success) || tc->m_no_output)
return;
std::lock_guard<std::mutex> lock(mutex);
logTestStart();
- file_line_to_stream(s, rb.m_file, rb.m_line, " ");
+ file_line_to_stream(rb.m_file, rb.m_line, " ");
successOrFailColoredStringToStream(!rb.m_failed, rb.m_at);
- if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) ==
- 0) //!OCLINT bitwise operator in conditional
- s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) "
- << Color::None;
- if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional
- s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n";
- } else if((rb.m_at & assertType::is_throws_as) &&
- (rb.m_at & assertType::is_throws_with)) { //!OCLINT
- s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
- << rb.m_exception_string << "\", " << rb.m_exception_type << " ) " << Color::None;
- if(rb.m_threw) {
- if(!rb.m_failed) {
- s << "threw as expected!\n";
- } else {
- s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n";
- }
- } else {
- s << "did NOT throw at all!\n";
- }
- } else if(rb.m_at &
- assertType::is_throws_as) { //!OCLINT bitwise operator in conditional
- s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", "
- << rb.m_exception_type << " ) " << Color::None
- << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" :
- "threw a DIFFERENT exception: ") :
- "did NOT throw at all!")
- << Color::Cyan << rb.m_exception << "\n";
- } else if(rb.m_at &
- assertType::is_throws_with) { //!OCLINT bitwise operator in conditional
- s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \""
- << rb.m_exception_string << "\" ) " << Color::None
- << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" :
- "threw a DIFFERENT exception: ") :
- "did NOT throw at all!")
- << Color::Cyan << rb.m_exception << "\n";
- } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional
- s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan
- << rb.m_exception << "\n";
- } else {
- s << (rb.m_threw ? "THREW exception: " :
- (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n"));
- if(rb.m_threw)
- s << rb.m_exception << "\n";
- else
- s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n";
- }
+ fulltext_log_assert_to_stream(s, rb);
log_contexts();
}
void log_message(const MessageData& mb) override {
+ if(tc->m_no_output)
+ return;
+
std::lock_guard<std::mutex> lock(mutex);
logTestStart();
- file_line_to_stream(s, mb.m_file, mb.m_line, " ");
+ file_line_to_stream(mb.m_file, mb.m_line, " ");
s << getSuccessOrFailColor(false, mb.m_severity)
<< getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity,
"MESSAGE") << ": ";
@@ -5372,8 +5966,10 @@
bool with_col = g_no_colors; \
g_no_colors = false; \
ConsoleReporter::func(arg); \
- DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
- oss.str(""); \
+ if(oss.tellp() != std::streampos{}) { \
+ DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
+ oss.str(""); \
+ } \
g_no_colors = with_col; \
}
@@ -5560,7 +6156,7 @@
#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \
if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \
parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \
- p->var = !!intRes; \
+ p->var = static_cast<bool>(intRes); \
else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \
parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \
p->var = true; \
@@ -5606,7 +6202,9 @@
DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC));
DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false);
DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false);
+ DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false);
DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false);
+ DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false);
// clang-format on
if(withDefaults) {
@@ -5662,6 +6260,7 @@
// allows the user to override procedurally the int/bool options from the command line
void Context::setOption(const char* option, int value) {
setOption(option, toString(value).c_str());
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
}
// allows the user to override procedurally the string options from the command line
@@ -5702,7 +6301,11 @@
p->cout = &fstr;
}
+ FatalConditionHandler::allocateAltStackMem();
+
auto cleanup_and_return = [&]() {
+ FatalConditionHandler::freeAltStackMem();
+
if(fstr.is_open())
fstr.close();
@@ -5737,7 +6340,7 @@
p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs));
#ifdef DOCTEST_PLATFORM_WINDOWS
- if(isDebuggerActive())
+ if(isDebuggerActive() && p->no_debug_output == false)
p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs));
#endif // DOCTEST_PLATFORM_WINDOWS
@@ -5774,6 +6377,9 @@
first[i] = first[idxToSwap];
first[idxToSwap] = temp;
}
+ } else if(p->order_by.compare("none", true) == 0) {
+ // means no sorting - beneficial for death tests which call into the executable
+ // with a specific test case in mind - we don't want to slow down the startup times
}
}
@@ -5793,9 +6399,9 @@
if(tc.m_skip && !p->no_skip)
skip_me = true;
- if(!matchesAny(tc.m_file, p->filters[0], true, p->case_sensitive))
+ if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive))
skip_me = true;
- if(matchesAny(tc.m_file, p->filters[1], false, p->case_sensitive))
+ if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive))
skip_me = true;
if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive))
skip_me = true;
@@ -5873,10 +6479,13 @@
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
try {
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
+// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method)
+DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable
FatalConditionHandler fatalConditionHandler; // Handle signals
// execute the test
tc.m_test();
fatalConditionHandler.reset();
+DOCTEST_MSVC_SUPPRESS_WARNING_POP
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
} catch(const TestFailureException&) {
p->failure_flags |= TestCaseFailureReason::AssertFailure;
@@ -5968,4 +6577,4 @@
DOCTEST_GCC_SUPPRESS_WARNING_POP
#endif // DOCTEST_LIBRARY_IMPLEMENTATION
-#endif // DOCTEST_CONFIG_IMPLEMENT
+#endif // DOCTEST_CONFIG_IMPLEMENT
\ No newline at end of file
diff --git a/third_party/include/nlohmann/LICENSE.MIT b/third_party/include/nlohmann/LICENSE.MIT
index 00599af..f0622d6 100644
--- a/third_party/include/nlohmann/LICENSE.MIT
+++ b/third_party/include/nlohmann/LICENSE.MIT
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2013-2017 Niels Lohmann
+Copyright (c) 2013-2021 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/third_party/include/nlohmann/json.hpp b/third_party/include/nlohmann/json.hpp
index cc822a5..a70aaf8 100644
--- a/third_party/include/nlohmann/json.hpp
+++ b/third_party/include/nlohmann/json.hpp
@@ -1,7 +1,7 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++
-| | |__ | | | | | | version 3.8.0
+| | |__ | | | | | | version 3.9.1
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@@ -31,11 +31,10 @@
#define INCLUDE_NLOHMANN_JSON_HPP_
#define NLOHMANN_JSON_VERSION_MAJOR 3
-#define NLOHMANN_JSON_VERSION_MINOR 8
-#define NLOHMANN_JSON_VERSION_PATCH 0
+#define NLOHMANN_JSON_VERSION_MINOR 9
+#define NLOHMANN_JSON_VERSION_PATCH 1
#include <algorithm> // all_of, find, for_each
-#include <cassert> // assert
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <functional> // hash, less
#include <initializer_list> // initializer_list
@@ -67,16 +66,6 @@
#include <utility> // pair, declval
#include <valarray> // valarray
-// #include <nlohmann/detail/boolean_operators.hpp>
-
-
-// Header <ciso646> is removed in C++20.
-// See <https://github.com/nlohmann/json/issues/2089> for more information.
-
-#if __cplusplus <= 201703L
- #include <ciso646> // and, not, or
-#endif
-
// #include <nlohmann/detail/exceptions.hpp>
@@ -2048,7 +2037,11 @@
#endif
// C++ language standard detection
-#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
+#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
+ #define JSON_HAS_CPP_20
+ #define JSON_HAS_CPP_17
+ #define JSON_HAS_CPP_14
+#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
@@ -2101,6 +2094,12 @@
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
#endif
+// allow to override assert
+#if !defined(JSON_ASSERT)
+ #include <cassert> // assert
+ #define JSON_ASSERT(x) assert(x)
+#endif
+
/*!
@brief macro to briefly define a mapping between an enum and JSON
@def NLOHMANN_JSON_SERIALIZE_ENUM
@@ -2149,6 +2148,170 @@
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer, BinaryType>
+// Macros to simplify conversion from/to types
+
+#define NLOHMANN_JSON_EXPAND( x ) x
+#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
+#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
+ NLOHMANN_JSON_PASTE64, \
+ NLOHMANN_JSON_PASTE63, \
+ NLOHMANN_JSON_PASTE62, \
+ NLOHMANN_JSON_PASTE61, \
+ NLOHMANN_JSON_PASTE60, \
+ NLOHMANN_JSON_PASTE59, \
+ NLOHMANN_JSON_PASTE58, \
+ NLOHMANN_JSON_PASTE57, \
+ NLOHMANN_JSON_PASTE56, \
+ NLOHMANN_JSON_PASTE55, \
+ NLOHMANN_JSON_PASTE54, \
+ NLOHMANN_JSON_PASTE53, \
+ NLOHMANN_JSON_PASTE52, \
+ NLOHMANN_JSON_PASTE51, \
+ NLOHMANN_JSON_PASTE50, \
+ NLOHMANN_JSON_PASTE49, \
+ NLOHMANN_JSON_PASTE48, \
+ NLOHMANN_JSON_PASTE47, \
+ NLOHMANN_JSON_PASTE46, \
+ NLOHMANN_JSON_PASTE45, \
+ NLOHMANN_JSON_PASTE44, \
+ NLOHMANN_JSON_PASTE43, \
+ NLOHMANN_JSON_PASTE42, \
+ NLOHMANN_JSON_PASTE41, \
+ NLOHMANN_JSON_PASTE40, \
+ NLOHMANN_JSON_PASTE39, \
+ NLOHMANN_JSON_PASTE38, \
+ NLOHMANN_JSON_PASTE37, \
+ NLOHMANN_JSON_PASTE36, \
+ NLOHMANN_JSON_PASTE35, \
+ NLOHMANN_JSON_PASTE34, \
+ NLOHMANN_JSON_PASTE33, \
+ NLOHMANN_JSON_PASTE32, \
+ NLOHMANN_JSON_PASTE31, \
+ NLOHMANN_JSON_PASTE30, \
+ NLOHMANN_JSON_PASTE29, \
+ NLOHMANN_JSON_PASTE28, \
+ NLOHMANN_JSON_PASTE27, \
+ NLOHMANN_JSON_PASTE26, \
+ NLOHMANN_JSON_PASTE25, \
+ NLOHMANN_JSON_PASTE24, \
+ NLOHMANN_JSON_PASTE23, \
+ NLOHMANN_JSON_PASTE22, \
+ NLOHMANN_JSON_PASTE21, \
+ NLOHMANN_JSON_PASTE20, \
+ NLOHMANN_JSON_PASTE19, \
+ NLOHMANN_JSON_PASTE18, \
+ NLOHMANN_JSON_PASTE17, \
+ NLOHMANN_JSON_PASTE16, \
+ NLOHMANN_JSON_PASTE15, \
+ NLOHMANN_JSON_PASTE14, \
+ NLOHMANN_JSON_PASTE13, \
+ NLOHMANN_JSON_PASTE12, \
+ NLOHMANN_JSON_PASTE11, \
+ NLOHMANN_JSON_PASTE10, \
+ NLOHMANN_JSON_PASTE9, \
+ NLOHMANN_JSON_PASTE8, \
+ NLOHMANN_JSON_PASTE7, \
+ NLOHMANN_JSON_PASTE6, \
+ NLOHMANN_JSON_PASTE5, \
+ NLOHMANN_JSON_PASTE4, \
+ NLOHMANN_JSON_PASTE3, \
+ NLOHMANN_JSON_PASTE2, \
+ NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
+#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
+#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
+#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
+#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
+#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
+#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
+#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
+#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
+#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
+#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
+#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
+#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
+#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
+#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
+#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
+#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
+#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
+#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
+#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
+#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
+#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
+#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
+#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
+#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
+#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
+#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
+#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
+#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
+#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
+#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
+#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
+#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
+#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
+#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
+#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
+#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
+#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
+#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
+#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
+#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
+#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
+#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
+#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
+#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
+#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
+#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
+#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
+#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
+#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
+#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
+#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
+#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
+#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
+#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
+#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
+#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
+#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
+#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
+#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
+#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
+#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
+#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
+#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
+
+#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;
+#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
+
+/*!
+@brief macro
+@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
+@since version 3.9.0
+*/
+#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
+ friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+ friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
+
+/*!
+@brief macro
+@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
+@since version 3.9.0
+*/
+#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
+ inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+ inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
+
+#ifndef JSON_USE_IMPLICIT_CONVERSIONS
+ #define JSON_USE_IMPLICIT_CONVERSIONS 1
+#endif
+
+#if JSON_USE_IMPLICIT_CONVERSIONS
+ #define JSON_EXPLICIT
+#else
+ #define JSON_EXPLICIT explicit
+#endif
+
namespace nlohmann
{
@@ -2240,6 +2403,7 @@
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).
+json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed.
@note For an input with n bytes, 1 is the index of the first character and n+1
is the index of the terminating null byte or the end of file. This also
@@ -2428,7 +2592,7 @@
json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.
json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
-json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. |
+json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) |
json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |
json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |
@@ -2506,9 +2670,6 @@
#include <cstddef> // size_t
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
-// #include <nlohmann/detail/boolean_operators.hpp>
-
-
namespace nlohmann
{
namespace detail
@@ -2574,8 +2735,6 @@
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
#include <utility> // declval
-// #include <nlohmann/detail/boolean_operators.hpp>
-
// #include <nlohmann/detail/iterators/iterator_traits.hpp>
@@ -2588,11 +2747,11 @@
{
namespace detail
{
-template <typename ...Ts> struct make_void
+template<typename ...Ts> struct make_void
{
using type = void;
};
-template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
+template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
} // namespace detail
} // namespace nlohmann
@@ -2603,10 +2762,10 @@
{
namespace detail
{
-template <typename It, typename = void>
+template<typename It, typename = void>
struct iterator_types {};
-template <typename It>
+template<typename It>
struct iterator_types <
It,
void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
@@ -2621,18 +2780,18 @@
// This is required as some compilers implement std::iterator_traits in a way that
// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
-template <typename T, typename = void>
+template<typename T, typename = void>
struct iterator_traits
{
};
-template <typename T>
+template<typename T>
struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
: iterator_types<T>
{
};
-template <typename T>
+template<typename T>
struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
{
using iterator_category = std::random_access_iterator_tag;
@@ -2671,39 +2830,39 @@
void operator=(nonesuch&&) = delete;
};
-template <class Default,
- class AlwaysVoid,
- template <class...> class Op,
- class... Args>
+template<class Default,
+ class AlwaysVoid,
+ template<class...> class Op,
+ class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
-template <class Default, template <class...> class Op, class... Args>
+template<class Default, template<class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = Op<Args...>;
};
-template <template <class...> class Op, class... Args>
+template<template<class...> class Op, class... Args>
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
-template <template <class...> class Op, class... Args>
+template<template<class...> class Op, class... Args>
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
-template <class Default, template <class...> class Op, class... Args>
+template<class Default, template<class...> class Op, class... Args>
using detected_or = detector<Default, void, Op, Args...>;
-template <class Default, template <class...> class Op, class... Args>
+template<class Default, template<class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
-template <class Expected, template <class...> class Op, class... Args>
+template<class Expected, template<class...> class Op, class... Args>
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
-template <class To, template <class...> class Op, class... Args>
+template<class To, template<class...> class Op, class... Args>
using is_detected_convertible =
std::is_convertible<detected_t<Op, Args...>, To>;
} // namespace detail
@@ -2772,6 +2931,19 @@
@since version 1.0.0
*/
using json = basic_json<>;
+
+template<class Key, class T, class IgnoredLess, class Allocator>
+struct ordered_map;
+
+/*!
+@brief ordered JSON class
+
+This type preserves the insertion order of object keys.
+
+@since version 3.9.0
+*/
+using ordered_json = basic_json<nlohmann::ordered_map>;
+
} // namespace nlohmann
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
@@ -2811,59 +2983,69 @@
// json_ref helpers //
//////////////////////
-template <typename>
+template<typename>
class json_ref;
template<typename>
struct is_json_ref : std::false_type {};
-template <typename T>
+template<typename T>
struct is_json_ref<json_ref<T>> : std::true_type {};
//////////////////////////
// aliases for detected //
//////////////////////////
-template <typename T>
+template<typename T>
using mapped_type_t = typename T::mapped_type;
-template <typename T>
+template<typename T>
using key_type_t = typename T::key_type;
-template <typename T>
+template<typename T>
using value_type_t = typename T::value_type;
-template <typename T>
+template<typename T>
using difference_type_t = typename T::difference_type;
-template <typename T>
+template<typename T>
using pointer_t = typename T::pointer;
-template <typename T>
+template<typename T>
using reference_t = typename T::reference;
-template <typename T>
+template<typename T>
using iterator_category_t = typename T::iterator_category;
-template <typename T>
+template<typename T>
using iterator_t = typename T::iterator;
-template <typename T, typename... Args>
+template<typename T, typename... Args>
using to_json_function = decltype(T::to_json(std::declval<Args>()...));
-template <typename T, typename... Args>
+template<typename T, typename... Args>
using from_json_function = decltype(T::from_json(std::declval<Args>()...));
-template <typename T, typename U>
+template<typename T, typename U>
using get_template_function = decltype(std::declval<T>().template get<U>());
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
-template <typename BasicJsonType, typename T, typename = void>
+template<typename BasicJsonType, typename T, typename = void>
struct has_from_json : std::false_type {};
+// trait checking if j.get<T> is valid
+// use this trait instead of std::is_constructible or std::is_convertible,
+// both rely on, or make use of implicit conversions, and thus fail when T
+// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
template <typename BasicJsonType, typename T>
-struct has_from_json<BasicJsonType, T,
- enable_if_t<not is_basic_json<T>::value>>
+struct is_getable
+{
+ static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
+};
+
+template<typename BasicJsonType, typename T>
+struct has_from_json < BasicJsonType, T,
+ enable_if_t < !is_basic_json<T>::value >>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;
@@ -2874,11 +3056,11 @@
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types
-template <typename BasicJsonType, typename T, typename = void>
+template<typename BasicJsonType, typename T, typename = void>
struct has_non_default_from_json : std::false_type {};
template<typename BasicJsonType, typename T>
-struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
+struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;
@@ -2889,11 +3071,11 @@
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
-template <typename BasicJsonType, typename T, typename = void>
+template<typename BasicJsonType, typename T, typename = void>
struct has_to_json : std::false_type {};
-template <typename BasicJsonType, typename T>
-struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
+template<typename BasicJsonType, typename T>
+struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;
@@ -2907,10 +3089,10 @@
// is_ functions //
///////////////////
-template <typename T, typename = void>
+template<typename T, typename = void>
struct is_iterator_traits : std::false_type {};
-template <typename T>
+template<typename T>
struct is_iterator_traits<iterator_traits<T>>
{
private:
@@ -2927,20 +3109,20 @@
// source: https://stackoverflow.com/a/37193089/4116453
-template <typename T, typename = void>
+template<typename T, typename = void>
struct is_complete_type : std::false_type {};
-template <typename T>
+template<typename T>
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
-template <typename BasicJsonType, typename CompatibleObjectType,
- typename = void>
+template<typename BasicJsonType, typename CompatibleObjectType,
+ typename = void>
struct is_compatible_object_type_impl : std::false_type {};
-template <typename BasicJsonType, typename CompatibleObjectType>
+template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type_impl <
BasicJsonType, CompatibleObjectType,
- enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and
+ enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
is_detected<key_type_t, CompatibleObjectType>::value >>
{
@@ -2949,53 +3131,53 @@
// macOS's is_constructible does not play well with nonesuch...
static constexpr bool value =
std::is_constructible<typename object_t::key_type,
- typename CompatibleObjectType::key_type>::value and
+ typename CompatibleObjectType::key_type>::value &&
std::is_constructible<typename object_t::mapped_type,
typename CompatibleObjectType::mapped_type>::value;
};
-template <typename BasicJsonType, typename CompatibleObjectType>
+template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
-template <typename BasicJsonType, typename ConstructibleObjectType,
- typename = void>
+template<typename BasicJsonType, typename ConstructibleObjectType,
+ typename = void>
struct is_constructible_object_type_impl : std::false_type {};
-template <typename BasicJsonType, typename ConstructibleObjectType>
+template<typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type_impl <
BasicJsonType, ConstructibleObjectType,
- enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value and
+ enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
is_detected<key_type_t, ConstructibleObjectType>::value >>
{
using object_t = typename BasicJsonType::object_t;
static constexpr bool value =
- (std::is_default_constructible<ConstructibleObjectType>::value and
- (std::is_move_assignable<ConstructibleObjectType>::value or
- std::is_copy_assignable<ConstructibleObjectType>::value) and
+ (std::is_default_constructible<ConstructibleObjectType>::value &&
+ (std::is_move_assignable<ConstructibleObjectType>::value ||
+ std::is_copy_assignable<ConstructibleObjectType>::value) &&
(std::is_constructible<typename ConstructibleObjectType::key_type,
- typename object_t::key_type>::value and
+ typename object_t::key_type>::value &&
std::is_same <
typename object_t::mapped_type,
- typename ConstructibleObjectType::mapped_type >::value)) or
+ typename ConstructibleObjectType::mapped_type >::value)) ||
(has_from_json<BasicJsonType,
- typename ConstructibleObjectType::mapped_type>::value or
+ typename ConstructibleObjectType::mapped_type>::value ||
has_non_default_from_json <
BasicJsonType,
typename ConstructibleObjectType::mapped_type >::value);
};
-template <typename BasicJsonType, typename ConstructibleObjectType>
+template<typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type
: is_constructible_object_type_impl<BasicJsonType,
ConstructibleObjectType> {};
-template <typename BasicJsonType, typename CompatibleStringType,
- typename = void>
+template<typename BasicJsonType, typename CompatibleStringType,
+ typename = void>
struct is_compatible_string_type_impl : std::false_type {};
-template <typename BasicJsonType, typename CompatibleStringType>
+template<typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_string_type_impl <
BasicJsonType, CompatibleStringType,
enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
@@ -3005,15 +3187,15 @@
std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
};
-template <typename BasicJsonType, typename ConstructibleStringType>
+template<typename BasicJsonType, typename ConstructibleStringType>
struct is_compatible_string_type
: is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
-template <typename BasicJsonType, typename ConstructibleStringType,
- typename = void>
+template<typename BasicJsonType, typename ConstructibleStringType,
+ typename = void>
struct is_constructible_string_type_impl : std::false_type {};
-template <typename BasicJsonType, typename ConstructibleStringType>
+template<typename BasicJsonType, typename ConstructibleStringType>
struct is_constructible_string_type_impl <
BasicJsonType, ConstructibleStringType,
enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
@@ -3024,55 +3206,55 @@
typename BasicJsonType::string_t>::value;
};
-template <typename BasicJsonType, typename ConstructibleStringType>
+template<typename BasicJsonType, typename ConstructibleStringType>
struct is_constructible_string_type
: is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
-template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
+template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
struct is_compatible_array_type_impl : std::false_type {};
-template <typename BasicJsonType, typename CompatibleArrayType>
+template<typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType,
- enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and
- is_detected<iterator_t, CompatibleArrayType>::value and
+ enable_if_t < is_detected<value_type_t, CompatibleArrayType>::value&&
+ is_detected<iterator_t, CompatibleArrayType>::value&&
// This is needed because json_reverse_iterator has a ::iterator type...
// Therefore it is detected as a CompatibleArrayType.
// The real fix would be to have an Iterable concept.
- not is_iterator_traits<
- iterator_traits<CompatibleArrayType>>::value >>
+ !is_iterator_traits <
+ iterator_traits<CompatibleArrayType >>::value >>
{
static constexpr bool value =
std::is_constructible<BasicJsonType,
typename CompatibleArrayType::value_type>::value;
};
-template <typename BasicJsonType, typename CompatibleArrayType>
+template<typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
-template <typename BasicJsonType, typename ConstructibleArrayType, typename = void>
+template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
struct is_constructible_array_type_impl : std::false_type {};
-template <typename BasicJsonType, typename ConstructibleArrayType>
+template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl <
BasicJsonType, ConstructibleArrayType,
enable_if_t<std::is_same<ConstructibleArrayType,
typename BasicJsonType::value_type>::value >>
: std::true_type {};
-template <typename BasicJsonType, typename ConstructibleArrayType>
+template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl <
BasicJsonType, ConstructibleArrayType,
- enable_if_t<not std::is_same<ConstructibleArrayType,
- typename BasicJsonType::value_type>::value and
- std::is_default_constructible<ConstructibleArrayType>::value and
-(std::is_move_assignable<ConstructibleArrayType>::value or
- std::is_copy_assignable<ConstructibleArrayType>::value) and
-is_detected<value_type_t, ConstructibleArrayType>::value and
-is_detected<iterator_t, ConstructibleArrayType>::value and
-is_complete_type<
-detected_t<value_type_t, ConstructibleArrayType>>::value >>
+ enable_if_t < !std::is_same<ConstructibleArrayType,
+ typename BasicJsonType::value_type>::value&&
+ std::is_default_constructible<ConstructibleArrayType>::value&&
+(std::is_move_assignable<ConstructibleArrayType>::value ||
+ std::is_copy_assignable<ConstructibleArrayType>::value)&&
+is_detected<value_type_t, ConstructibleArrayType>::value&&
+is_detected<iterator_t, ConstructibleArrayType>::value&&
+is_complete_type <
+detected_t<value_type_t, ConstructibleArrayType >>::value >>
{
static constexpr bool value =
// This is needed because json_reverse_iterator has a ::iterator type,
@@ -3080,30 +3262,30 @@
// base class `iterator`... Therefore it is detected as a
// ConstructibleArrayType. The real fix would be to have an Iterable
// concept.
- not is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value and
+ !is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value &&
(std::is_same<typename ConstructibleArrayType::value_type,
- typename BasicJsonType::array_t::value_type>::value or
+ typename BasicJsonType::array_t::value_type>::value ||
has_from_json<BasicJsonType,
- typename ConstructibleArrayType::value_type>::value or
+ typename ConstructibleArrayType::value_type>::value ||
has_non_default_from_json <
BasicJsonType, typename ConstructibleArrayType::value_type >::value);
};
-template <typename BasicJsonType, typename ConstructibleArrayType>
+template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type
: is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
-template <typename RealIntegerType, typename CompatibleNumberIntegerType,
- typename = void>
+template<typename RealIntegerType, typename CompatibleNumberIntegerType,
+ typename = void>
struct is_compatible_integer_type_impl : std::false_type {};
-template <typename RealIntegerType, typename CompatibleNumberIntegerType>
+template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl <
RealIntegerType, CompatibleNumberIntegerType,
- enable_if_t<std::is_integral<RealIntegerType>::value and
- std::is_integral<CompatibleNumberIntegerType>::value and
- not std::is_same<bool, CompatibleNumberIntegerType>::value >>
+ enable_if_t < std::is_integral<RealIntegerType>::value&&
+ std::is_integral<CompatibleNumberIntegerType>::value&&
+ !std::is_same<bool, CompatibleNumberIntegerType>::value >>
{
// is there an assert somewhere on overflows?
using RealLimits = std::numeric_limits<RealIntegerType>;
@@ -3111,20 +3293,20 @@
static constexpr auto value =
std::is_constructible<RealIntegerType,
- CompatibleNumberIntegerType>::value and
- CompatibleLimits::is_integer and
+ CompatibleNumberIntegerType>::value &&
+ CompatibleLimits::is_integer &&
RealLimits::is_signed == CompatibleLimits::is_signed;
};
-template <typename RealIntegerType, typename CompatibleNumberIntegerType>
+template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type
: is_compatible_integer_type_impl<RealIntegerType,
CompatibleNumberIntegerType> {};
-template <typename BasicJsonType, typename CompatibleType, typename = void>
+template<typename BasicJsonType, typename CompatibleType, typename = void>
struct is_compatible_type_impl: std::false_type {};
-template <typename BasicJsonType, typename CompatibleType>
+template<typename BasicJsonType, typename CompatibleType>
struct is_compatible_type_impl <
BasicJsonType, CompatibleType,
enable_if_t<is_complete_type<CompatibleType>::value >>
@@ -3133,7 +3315,7 @@
has_to_json<BasicJsonType, CompatibleType>::value;
};
-template <typename BasicJsonType, typename CompatibleType>
+template<typename BasicJsonType, typename CompatibleType>
struct is_compatible_type
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
@@ -3144,10 +3326,10 @@
struct conjunction<B1, Bn...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
-template <typename T1, typename T2>
+template<typename T1, typename T2>
struct is_constructible_tuple : std::false_type {};
-template <typename T1, typename... Args>
+template<typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<std::is_constructible<T1, Args>...> {};
} // namespace detail
} // namespace nlohmann
@@ -3160,9 +3342,6 @@
#include <cstdint> // uint8_t
#include <string> // string
-// #include <nlohmann/detail/boolean_operators.hpp>
-
-
namespace nlohmann
{
namespace detail
@@ -3233,7 +3412,7 @@
const auto l_index = static_cast<std::size_t>(lhs);
const auto r_index = static_cast<std::size_t>(rhs);
- return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];
+ return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
}
} // namespace detail
} // namespace nlohmann
@@ -3246,7 +3425,7 @@
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_null()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
{
JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
}
@@ -3254,10 +3433,10 @@
}
// overloads for basic_json template parameters
-template<typename BasicJsonType, typename ArithmeticType,
- enable_if_t<std::is_arithmetic<ArithmeticType>::value and
- not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
- int> = 0>
+template < typename BasicJsonType, typename ArithmeticType,
+ enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
+ !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
+ int > = 0 >
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{
switch (static_cast<value_t>(j))
@@ -3286,7 +3465,7 @@
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_boolean()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
{
JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name())));
}
@@ -3296,7 +3475,7 @@
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_string()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
}
@@ -3306,13 +3485,13 @@
template <
typename BasicJsonType, typename ConstructibleStringType,
enable_if_t <
- is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and
- not std::is_same<typename BasicJsonType::string_t,
- ConstructibleStringType>::value,
+ is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&
+ !std::is_same<typename BasicJsonType::string_t,
+ ConstructibleStringType>::value,
int > = 0 >
void from_json(const BasicJsonType& j, ConstructibleStringType& s)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_string()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
}
@@ -3349,10 +3528,10 @@
// forward_list doesn't have an insert method
template<typename BasicJsonType, typename T, typename Allocator,
- enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
+ enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
@@ -3366,18 +3545,22 @@
// valarray doesn't have an insert method
template<typename BasicJsonType, typename T,
- enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
+ enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
void from_json(const BasicJsonType& j, std::valarray<T>& l)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
l.resize(j.size());
- std::copy(j.begin(), j.end(), std::begin(l));
+ std::transform(j.begin(), j.end(), std::begin(l),
+ [](const BasicJsonType & elem)
+ {
+ return elem.template get<T>();
+ });
}
-template <typename BasicJsonType, typename T, std::size_t N>
+template<typename BasicJsonType, typename T, std::size_t N>
auto from_json(const BasicJsonType& j, T (&arr)[N])
-> decltype(j.template get<T>(), void())
{
@@ -3393,7 +3576,7 @@
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
}
-template <typename BasicJsonType, typename T, std::size_t N>
+template<typename BasicJsonType, typename T, std::size_t N>
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
priority_tag<2> /*unused*/)
-> decltype(j.template get<T>(), void())
@@ -3425,7 +3608,7 @@
arr = std::move(ret);
}
-template <typename BasicJsonType, typename ConstructibleArrayType>
+template<typename BasicJsonType, typename ConstructibleArrayType>
void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
priority_tag<0> /*unused*/)
{
@@ -3443,20 +3626,20 @@
arr = std::move(ret);
}
-template <typename BasicJsonType, typename ConstructibleArrayType,
- enable_if_t <
- is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and
- not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and
- not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and
- not std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value and
- not is_basic_json<ConstructibleArrayType>::value,
- int > = 0 >
+template < typename BasicJsonType, typename ConstructibleArrayType,
+ enable_if_t <
+ is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
+ !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
+ !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
+ !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
+ !is_basic_json<ConstructibleArrayType>::value,
+ int > = 0 >
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
j.template get<typename ConstructibleArrayType::value_type>(),
void())
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " +
std::string(j.type_name())));
@@ -3465,10 +3648,10 @@
from_json_array_impl(j, arr, priority_tag<3> {});
}
-template <typename BasicJsonType>
+template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_binary()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
{
JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name())));
}
@@ -3480,7 +3663,7 @@
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
{
JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name())));
}
@@ -3502,14 +3685,14 @@
// (BooleanType, etc..); note: Is it really necessary to provide explicit
// overloads for boolean_t etc. in case of a custom BooleanType which is not
// an arithmetic type?
-template<typename BasicJsonType, typename ArithmeticType,
- enable_if_t <
- std::is_arithmetic<ArithmeticType>::value and
- not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and
- not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and
- not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and
- not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
- int> = 0>
+template < typename BasicJsonType, typename ArithmeticType,
+ enable_if_t <
+ std::is_arithmetic<ArithmeticType>::value&&
+ !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
+ !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
+ !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
+ !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
+ int > = 0 >
void from_json(const BasicJsonType& j, ArithmeticType& val)
{
switch (static_cast<value_t>(j))
@@ -3558,19 +3741,19 @@
from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
}
-template <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
- typename = enable_if_t<not std::is_constructible<
- typename BasicJsonType::string_t, Key>::value>>
+template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
+ typename = enable_if_t < !std::is_constructible <
+ typename BasicJsonType::string_t, Key >::value >>
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
m.clear();
for (const auto& p : j)
{
- if (JSON_HEDLEY_UNLIKELY(not p.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
}
@@ -3578,19 +3761,19 @@
}
}
-template <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
- typename = enable_if_t<not std::is_constructible<
- typename BasicJsonType::string_t, Key>::value>>
+template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
+ typename = enable_if_t < !std::is_constructible <
+ typename BasicJsonType::string_t, Key >::value >>
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
{
- if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
m.clear();
for (const auto& p : j)
{
- if (JSON_HEDLEY_UNLIKELY(not p.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
}
@@ -3631,8 +3814,6 @@
#include <valarray> // valarray
#include <vector> // vector
-// #include <nlohmann/detail/boolean_operators.hpp>
-
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
@@ -3653,9 +3834,11 @@
template<typename string_type>
void int_to_string( string_type& target, std::size_t value )
{
- target = std::to_string(value);
+ // For ADL
+ using std::to_string;
+ target = to_string(value);
}
-template <typename IteratorType> class iteration_proxy_value
+template<typename IteratorType> class iteration_proxy_value
{
public:
using difference_type = std::ptrdiff_t;
@@ -3710,7 +3893,7 @@
/// return key of the iterator
const string_type& key() const
{
- assert(anchor.m_object != nullptr);
+ JSON_ASSERT(anchor.m_object != nullptr);
switch (anchor.m_object->type())
{
@@ -3769,7 +3952,7 @@
// Structured Bindings Support
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
// And see https://github.com/nlohmann/json/pull/1391
-template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
+template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
{
return i.key();
@@ -3777,7 +3960,7 @@
// Structured Bindings Support
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
// And see https://github.com/nlohmann/json/pull/1391
-template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
+template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
{
return i.value();
@@ -3796,11 +3979,11 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
-template <typename IteratorType>
+template<typename IteratorType>
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
: public std::integral_constant<std::size_t, 2> {};
-template <std::size_t N, typename IteratorType>
+template<std::size_t N, typename IteratorType>
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
{
public:
@@ -3861,9 +4044,9 @@
j.assert_invariant();
}
- template<typename BasicJsonType, typename CompatibleStringType,
- enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
- int> = 0>
+ template < typename BasicJsonType, typename CompatibleStringType,
+ enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
+ int > = 0 >
static void construct(BasicJsonType& j, const CompatibleStringType& str)
{
j.m_type = value_t::string;
@@ -3949,9 +4132,9 @@
j.assert_invariant();
}
- template<typename BasicJsonType, typename CompatibleArrayType,
- enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
- int> = 0>
+ template < typename BasicJsonType, typename CompatibleArrayType,
+ enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
+ int > = 0 >
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
{
using std::begin;
@@ -4008,8 +4191,8 @@
j.assert_invariant();
}
- template<typename BasicJsonType, typename CompatibleObjectType,
- enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>
+ template < typename BasicJsonType, typename CompatibleObjectType,
+ enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
{
using std::begin;
@@ -4080,20 +4263,20 @@
external_constructor<value_t::array>::construct(j, e);
}
-template <typename BasicJsonType, typename CompatibleArrayType,
- enable_if_t<is_compatible_array_type<BasicJsonType,
- CompatibleArrayType>::value and
- not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and
- not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
- not std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value and
- not is_basic_json<CompatibleArrayType>::value,
- int> = 0>
+template < typename BasicJsonType, typename CompatibleArrayType,
+ enable_if_t < is_compatible_array_type<BasicJsonType,
+ CompatibleArrayType>::value&&
+ !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
+ !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
+ !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
+ !is_basic_json<CompatibleArrayType>::value,
+ int > = 0 >
void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
{
external_constructor<value_t::array>::construct(j, arr);
}
-template <typename BasicJsonType>
+template<typename BasicJsonType>
void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
{
external_constructor<value_t::binary>::construct(j, bin);
@@ -4112,8 +4295,8 @@
external_constructor<value_t::array>::construct(j, std::move(arr));
}
-template<typename BasicJsonType, typename CompatibleObjectType,
- enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>
+template < typename BasicJsonType, typename CompatibleObjectType,
+ enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
{
external_constructor<value_t::object>::construct(j, obj);
@@ -4127,9 +4310,9 @@
template <
typename BasicJsonType, typename T, std::size_t N,
- enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
- const T(&)[N]>::value,
- int> = 0 >
+ enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
+ const T(&)[N]>::value,
+ int > = 0 >
void to_json(BasicJsonType& j, const T(&arr)[N])
{
external_constructor<value_t::array>::construct(j, arr);
@@ -4142,8 +4325,8 @@
}
// for https://github.com/nlohmann/json/pull/1134
-template < typename BasicJsonType, typename T,
- enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
+template<typename BasicJsonType, typename T,
+ enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
void to_json(BasicJsonType& j, const T& b)
{
j = { {b.key(), b.value()} };
@@ -4212,7 +4395,7 @@
@param[in,out] j JSON value to write to
@param[in] val value to read from
*/
- template <typename BasicJsonType, typename ValueType>
+ template<typename BasicJsonType, typename ValueType>
static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(
noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
-> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), void())
@@ -4391,20 +4574,136 @@
} // namespace nlohmann
-// #include <nlohmann/detail/boolean_operators.hpp>
-
// #include <nlohmann/detail/conversions/from_json.hpp>
// #include <nlohmann/detail/conversions/to_json.hpp>
// #include <nlohmann/detail/exceptions.hpp>
+// #include <nlohmann/detail/hash.hpp>
+
+
+#include <cstddef> // size_t, uint8_t
+#include <functional> // hash
+
+namespace nlohmann
+{
+namespace detail
+{
+
+// boost::hash_combine
+inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
+{
+ seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
+ return seed;
+}
+
+/*!
+@brief hash a JSON value
+
+The hash function tries to rely on std::hash where possible. Furthermore, the
+type of the JSON value is taken into account to have different hash values for
+null, 0, 0U, and false, etc.
+
+@tparam BasicJsonType basic_json specialization
+@param j JSON value to hash
+@return hash value of j
+*/
+template<typename BasicJsonType>
+std::size_t hash(const BasicJsonType& j)
+{
+ using string_t = typename BasicJsonType::string_t;
+ using number_integer_t = typename BasicJsonType::number_integer_t;
+ using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+ using number_float_t = typename BasicJsonType::number_float_t;
+
+ const auto type = static_cast<std::size_t>(j.type());
+ switch (j.type())
+ {
+ case BasicJsonType::value_t::null:
+ case BasicJsonType::value_t::discarded:
+ {
+ return combine(type, 0);
+ }
+
+ case BasicJsonType::value_t::object:
+ {
+ auto seed = combine(type, j.size());
+ for (const auto& element : j.items())
+ {
+ const auto h = std::hash<string_t> {}(element.key());
+ seed = combine(seed, h);
+ seed = combine(seed, hash(element.value()));
+ }
+ return seed;
+ }
+
+ case BasicJsonType::value_t::array:
+ {
+ auto seed = combine(type, j.size());
+ for (const auto& element : j)
+ {
+ seed = combine(seed, hash(element));
+ }
+ return seed;
+ }
+
+ case BasicJsonType::value_t::string:
+ {
+ const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
+ return combine(type, h);
+ }
+
+ case BasicJsonType::value_t::boolean:
+ {
+ const auto h = std::hash<bool> {}(j.template get<bool>());
+ return combine(type, h);
+ }
+
+ case BasicJsonType::value_t::number_integer:
+ {
+ const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
+ return combine(type, h);
+ }
+
+ case nlohmann::detail::value_t::number_unsigned:
+ {
+ const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
+ return combine(type, h);
+ }
+
+ case nlohmann::detail::value_t::number_float:
+ {
+ const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
+ return combine(type, h);
+ }
+
+ case nlohmann::detail::value_t::binary:
+ {
+ auto seed = combine(type, j.get_binary().size());
+ const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
+ seed = combine(seed, h);
+ seed = combine(seed, j.get_binary().subtype());
+ for (const auto byte : j.get_binary())
+ {
+ seed = combine(seed, std::hash<std::uint8_t> {}(byte));
+ }
+ return seed;
+ }
+
+ default: // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
+ }
+}
+
+} // namespace detail
+} // namespace nlohmann
+
// #include <nlohmann/detail/input/binary_reader.hpp>
#include <algorithm> // generate_n
#include <array> // array
-#include <cassert> // assert
#include <cmath> // ldexp
#include <cstddef> // size_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
@@ -4421,7 +4720,6 @@
#include <array> // array
-#include <cassert> // assert
#include <cstddef> // size_t
#include <cstdio> //FILE *
#include <cstring> // strlen
@@ -4459,7 +4757,7 @@
using char_type = char;
JSON_HEDLEY_NON_NULL(2)
- explicit file_input_adapter(std::FILE* f) noexcept
+ explicit file_input_adapter(std::FILE* f) noexcept
: m_file(f)
{}
@@ -4498,7 +4796,7 @@
{
// clear stream flags; we use underlying streambuf I/O, do not
// maintain ifstream flags, except eof
- if (is)
+ if (is != nullptr)
{
is->clear(is->rdstate() & std::ios::eofbit);
}
@@ -4513,7 +4811,7 @@
input_stream_adapter& operator=(input_stream_adapter&) = delete;
input_stream_adapter& operator=(input_stream_adapter&& rhs) = delete;
- input_stream_adapter(input_stream_adapter&& rhs) : is(rhs.is), sb(rhs.sb)
+ input_stream_adapter(input_stream_adapter&& rhs) noexcept : is(rhs.is), sb(rhs.sb)
{
rhs.is = nullptr;
rhs.sb = nullptr;
@@ -4673,7 +4971,7 @@
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
utf8_bytes_filled = 2;
}
- else if (0xD800 > wc or wc >= 0xE000)
+ else if (0xD800 > wc || wc >= 0xE000)
{
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
@@ -4682,7 +4980,7 @@
}
else
{
- if (JSON_HEDLEY_UNLIKELY(not input.empty()))
+ if (JSON_HEDLEY_UNLIKELY(!input.empty()))
{
const auto wc2 = static_cast<unsigned int>(input.get_character());
const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
@@ -4719,13 +5017,13 @@
{
fill_buffer<sizeof(WideCharType)>();
- assert(utf8_bytes_filled > 0);
- assert(utf8_bytes_index == 0);
+ JSON_ASSERT(utf8_bytes_filled > 0);
+ JSON_ASSERT(utf8_bytes_index == 0);
}
// use buffer
- assert(utf8_bytes_filled > 0);
- assert(utf8_bytes_index < utf8_bytes_filled);
+ JSON_ASSERT(utf8_bytes_filled > 0);
+ JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
return utf8_bytes[utf8_bytes_index++];
}
@@ -4825,15 +5123,15 @@
// Null-delimited strings, and the like.
template < typename CharT,
typename std::enable_if <
- std::is_pointer<CharT>::value and
- not std::is_array<CharT>::value and
- std::is_integral<typename std::remove_pointer<CharT>::type>::value and
+ std::is_pointer<CharT>::value&&
+ !std::is_array<CharT>::value&&
+ std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
sizeof(typename std::remove_pointer<CharT>::type) == 1,
int >::type = 0 >
contiguous_bytes_input_adapter input_adapter(CharT b)
{
auto length = std::strlen(reinterpret_cast<const char*>(b));
- auto ptr = reinterpret_cast<const char*>(b);
+ const auto* ptr = reinterpret_cast<const char*>(b);
return input_adapter(ptr, ptr + length);
}
@@ -4849,12 +5147,12 @@
class span_input_adapter
{
public:
- template<typename CharT,
- typename std::enable_if<
- std::is_pointer<CharT>::value and
- std::is_integral<typename std::remove_pointer<CharT>::type>::value and
- sizeof(typename std::remove_pointer<CharT>::type) == 1,
- int>::type = 0>
+ template < typename CharT,
+ typename std::enable_if <
+ std::is_pointer<CharT>::value&&
+ std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
+ sizeof(typename std::remove_pointer<CharT>::type) == 1,
+ int >::type = 0 >
span_input_adapter(CharT b, std::size_t l)
: ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}
@@ -4879,7 +5177,6 @@
// #include <nlohmann/detail/input/json_sax.hpp>
-#include <cassert> // assert
#include <cstddef>
#include <string> // string
#include <utility> // move
@@ -5099,7 +5396,7 @@
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
- if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
+ if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive object size: " + std::to_string(len)));
@@ -5125,7 +5422,7 @@
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
- if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
+ if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive array size: " + std::to_string(len)));
@@ -5140,30 +5437,15 @@
return true;
}
+ template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
- const detail::exception& ex)
+ const Exception& ex)
{
errored = true;
+ static_cast<void>(ex);
if (allow_exceptions)
{
- // determine the proper exception type from the id
- switch ((ex.id / 100) % 100)
- {
- case 1:
- JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
- case 4:
- JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
- // LCOV_EXCL_START
- case 2:
- JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
- case 3:
- JSON_THROW(*static_cast<const detail::type_error*>(&ex));
- case 5:
- JSON_THROW(*static_cast<const detail::other_error*>(&ex));
- default:
- assert(false);
- // LCOV_EXCL_STOP
- }
+ JSON_THROW(ex);
}
return false;
}
@@ -5190,7 +5472,7 @@
return &root;
}
- assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
+ JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
if (ref_stack.back()->is_array())
{
@@ -5198,8 +5480,8 @@
return &(ref_stack.back()->m_value.array->back());
}
- assert(ref_stack.back()->is_object());
- assert(object_element);
+ JSON_ASSERT(ref_stack.back()->is_object());
+ JSON_ASSERT(object_element);
*object_element = BasicJsonType(std::forward<Value>(v));
return object_element;
}
@@ -5295,7 +5577,7 @@
ref_stack.push_back(val.second);
// check object limit
- if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
+ if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len)));
}
@@ -5312,7 +5594,7 @@
key_keep_stack.push_back(keep);
// add discarded value at given key and store the reference for later
- if (keep and ref_stack.back())
+ if (keep && ref_stack.back())
{
object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
}
@@ -5322,18 +5604,18 @@
bool end_object()
{
- if (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
+ if (ref_stack.back() && !callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
{
// discard object
*ref_stack.back() = discarded;
}
- assert(not ref_stack.empty());
- assert(not keep_stack.empty());
+ JSON_ASSERT(!ref_stack.empty());
+ JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
- if (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_structured())
+ if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
{
// remove discarded value
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
@@ -5358,7 +5640,7 @@
ref_stack.push_back(val.second);
// check array limit
- if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
+ if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len)));
}
@@ -5373,20 +5655,20 @@
if (ref_stack.back())
{
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
- if (not keep)
+ if (!keep)
{
// discard array
*ref_stack.back() = discarded;
}
}
- assert(not ref_stack.empty());
- assert(not keep_stack.empty());
+ JSON_ASSERT(!ref_stack.empty());
+ JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
// remove discarded value
- if (not keep and not ref_stack.empty() and ref_stack.back()->is_array())
+ if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
{
ref_stack.back()->m_value.array->pop_back();
}
@@ -5394,30 +5676,15 @@
return true;
}
+ template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
- const detail::exception& ex)
+ const Exception& ex)
{
errored = true;
+ static_cast<void>(ex);
if (allow_exceptions)
{
- // determine the proper exception type from the id
- switch ((ex.id / 100) % 100)
- {
- case 1:
- JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
- case 4:
- JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
- // LCOV_EXCL_START
- case 2:
- JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
- case 3:
- JSON_THROW(*static_cast<const detail::type_error*>(&ex));
- case 5:
- JSON_THROW(*static_cast<const detail::other_error*>(&ex));
- default:
- assert(false);
- // LCOV_EXCL_STOP
- }
+ JSON_THROW(ex);
}
return false;
}
@@ -5446,11 +5713,11 @@
template<typename Value>
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
{
- assert(not keep_stack.empty());
+ JSON_ASSERT(!keep_stack.empty());
// do not handle this value if we know it would be added to a discarded
// container
- if (not keep_stack.back())
+ if (!keep_stack.back())
{
return {false, nullptr};
}
@@ -5459,10 +5726,10 @@
auto value = BasicJsonType(std::forward<Value>(v));
// check callback
- const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
+ const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
// do not handle this value if we just learnt it shall be discarded
- if (not keep)
+ if (!keep)
{
return {false, nullptr};
}
@@ -5475,13 +5742,13 @@
// skip this value if we already decided to skip the parent
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
- if (not ref_stack.back())
+ if (!ref_stack.back())
{
return {false, nullptr};
}
// we now only expect arrays and objects
- assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
+ JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
// array
if (ref_stack.back()->is_array())
@@ -5491,18 +5758,18 @@
}
// object
- assert(ref_stack.back()->is_object());
+ JSON_ASSERT(ref_stack.back()->is_object());
// check if we should store an element for the current key
- assert(not key_keep_stack.empty());
+ JSON_ASSERT(!key_keep_stack.empty());
const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back();
- if (not store_element)
+ if (!store_element)
{
return {false, nullptr};
}
- assert(object_element);
+ JSON_ASSERT(object_element);
*object_element = std::move(value);
return {true, object_element};
}
@@ -5606,2461 +5873,6 @@
} // namespace nlohmann
-// #include <nlohmann/detail/macro_scope.hpp>
-
-// #include <nlohmann/detail/meta/is_sax.hpp>
-
-
-#include <cstdint> // size_t
-#include <utility> // declval
-#include <string> // string
-
-// #include <nlohmann/detail/meta/detected.hpp>
-
-// #include <nlohmann/detail/meta/type_traits.hpp>
-
-
-namespace nlohmann
-{
-namespace detail
-{
-template <typename T>
-using null_function_t = decltype(std::declval<T&>().null());
-
-template <typename T>
-using boolean_function_t =
- decltype(std::declval<T&>().boolean(std::declval<bool>()));
-
-template <typename T, typename Integer>
-using number_integer_function_t =
- decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
-
-template <typename T, typename Unsigned>
-using number_unsigned_function_t =
- decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
-
-template <typename T, typename Float, typename String>
-using number_float_function_t = decltype(std::declval<T&>().number_float(
- std::declval<Float>(), std::declval<const String&>()));
-
-template <typename T, typename String>
-using string_function_t =
- decltype(std::declval<T&>().string(std::declval<String&>()));
-
-template <typename T>
-using start_object_function_t =
- decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
-
-template <typename T, typename String>
-using key_function_t =
- decltype(std::declval<T&>().key(std::declval<String&>()));
-
-template <typename T>
-using end_object_function_t = decltype(std::declval<T&>().end_object());
-
-template <typename T>
-using start_array_function_t =
- decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
-
-template <typename T>
-using end_array_function_t = decltype(std::declval<T&>().end_array());
-
-template <typename T, typename Exception>
-using parse_error_function_t = decltype(std::declval<T&>().parse_error(
- std::declval<std::size_t>(), std::declval<const std::string&>(),
- std::declval<const Exception&>()));
-
-template <typename SAX, typename BasicJsonType>
-struct is_sax
-{
- private:
- static_assert(is_basic_json<BasicJsonType>::value,
- "BasicJsonType must be of type basic_json<...>");
-
- using number_integer_t = typename BasicJsonType::number_integer_t;
- using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
- using number_float_t = typename BasicJsonType::number_float_t;
- using string_t = typename BasicJsonType::string_t;
- using exception_t = typename BasicJsonType::exception;
-
- public:
- static constexpr bool value =
- is_detected_exact<bool, null_function_t, SAX>::value &&
- is_detected_exact<bool, boolean_function_t, SAX>::value &&
- is_detected_exact<bool, number_integer_function_t, SAX,
- number_integer_t>::value &&
- is_detected_exact<bool, number_unsigned_function_t, SAX,
- number_unsigned_t>::value &&
- is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
- string_t>::value &&
- is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
- is_detected_exact<bool, start_object_function_t, SAX>::value &&
- is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
- is_detected_exact<bool, end_object_function_t, SAX>::value &&
- is_detected_exact<bool, start_array_function_t, SAX>::value &&
- is_detected_exact<bool, end_array_function_t, SAX>::value &&
- is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
-};
-
-template <typename SAX, typename BasicJsonType>
-struct is_sax_static_asserts
-{
- private:
- static_assert(is_basic_json<BasicJsonType>::value,
- "BasicJsonType must be of type basic_json<...>");
-
- using number_integer_t = typename BasicJsonType::number_integer_t;
- using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
- using number_float_t = typename BasicJsonType::number_float_t;
- using string_t = typename BasicJsonType::string_t;
- using exception_t = typename BasicJsonType::exception;
-
- public:
- static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
- "Missing/invalid function: bool null()");
- static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
- "Missing/invalid function: bool boolean(bool)");
- static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
- "Missing/invalid function: bool boolean(bool)");
- static_assert(
- is_detected_exact<bool, number_integer_function_t, SAX,
- number_integer_t>::value,
- "Missing/invalid function: bool number_integer(number_integer_t)");
- static_assert(
- is_detected_exact<bool, number_unsigned_function_t, SAX,
- number_unsigned_t>::value,
- "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
- static_assert(is_detected_exact<bool, number_float_function_t, SAX,
- number_float_t, string_t>::value,
- "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
- static_assert(
- is_detected_exact<bool, string_function_t, SAX, string_t>::value,
- "Missing/invalid function: bool string(string_t&)");
- static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
- "Missing/invalid function: bool start_object(std::size_t)");
- static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
- "Missing/invalid function: bool key(string_t&)");
- static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
- "Missing/invalid function: bool end_object()");
- static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
- "Missing/invalid function: bool start_array(std::size_t)");
- static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
- "Missing/invalid function: bool end_array()");
- static_assert(
- is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
- "Missing/invalid function: bool parse_error(std::size_t, const "
- "std::string&, const exception&)");
-};
-} // namespace detail
-} // namespace nlohmann
-
-// #include <nlohmann/detail/value_t.hpp>
-
-
-namespace nlohmann
-{
-namespace detail
-{
-
-/*!
-@brief determine system byte order
-
-@return true if and only if system's byte order is little endian
-
-@note from https://stackoverflow.com/a/1001328/266378
-*/
-static inline bool little_endianess(int num = 1) noexcept
-{
- return *reinterpret_cast<char*>(&num) == 1;
-}
-
-
-///////////////////
-// binary reader //
-///////////////////
-
-/*!
-@brief deserialization of CBOR, MessagePack, and UBJSON values
-*/
-template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
-class binary_reader
-{
- using number_integer_t = typename BasicJsonType::number_integer_t;
- using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
- using number_float_t = typename BasicJsonType::number_float_t;
- using string_t = typename BasicJsonType::string_t;
- using binary_t = typename BasicJsonType::binary_t;
- using json_sax_t = SAX;
- using char_type = typename InputAdapterType::char_type;
- using char_int_type = typename std::char_traits<char_type>::int_type;
-
- public:
- /*!
- @brief create a binary reader
-
- @param[in] adapter input adapter to read from
- */
- explicit binary_reader(InputAdapterType&& adapter) : ia(std::move(adapter))
- {
- (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
- }
-
- // make class move-only
- binary_reader(const binary_reader&) = delete;
- binary_reader(binary_reader&&) = default;
- binary_reader& operator=(const binary_reader&) = delete;
- binary_reader& operator=(binary_reader&&) = default;
- ~binary_reader() = default;
-
- /*!
- @param[in] format the binary format to parse
- @param[in] sax_ a SAX event processor
- @param[in] strict whether to expect the input to be consumed completed
-
- @return
- */
- JSON_HEDLEY_NON_NULL(3)
- bool sax_parse(const input_format_t format,
- json_sax_t* sax_,
- const bool strict = true)
- {
- sax = sax_;
- bool result = false;
-
- switch (format)
- {
- case input_format_t::bson:
- result = parse_bson_internal();
- break;
-
- case input_format_t::cbor:
- result = parse_cbor_internal();
- break;
-
- case input_format_t::msgpack:
- result = parse_msgpack_internal();
- break;
-
- case input_format_t::ubjson:
- result = parse_ubjson_internal();
- break;
-
- default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
- }
-
- // strict mode: next byte must be EOF
- if (result and strict)
- {
- if (format == input_format_t::ubjson)
- {
- get_ignore_noop();
- }
- else
- {
- get();
- }
-
- if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
- {
- return sax->parse_error(chars_read, get_token_string(),
- parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value")));
- }
- }
-
- return result;
- }
-
- private:
- //////////
- // BSON //
- //////////
-
- /*!
- @brief Reads in a BSON-object and passes it to the SAX-parser.
- @return whether a valid BSON-value was passed to the SAX parser
- */
- bool parse_bson_internal()
- {
- std::int32_t document_size;
- get_number<std::int32_t, true>(input_format_t::bson, document_size);
-
- if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
- {
- return false;
- }
-
- if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/false)))
- {
- return false;
- }
-
- return sax->end_object();
- }
-
- /*!
- @brief Parses a C-style string from the BSON input.
- @param[in, out] result A reference to the string variable where the read
- string is to be stored.
- @return `true` if the \x00-byte indicating the end of the string was
- encountered before the EOF; false` indicates an unexpected EOF.
- */
- bool get_bson_cstr(string_t& result)
- {
- auto out = std::back_inserter(result);
- while (true)
- {
- get();
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring")))
- {
- return false;
- }
- if (current == 0x00)
- {
- return true;
- }
- *out++ = static_cast<typename string_t::value_type>(current);
- }
-
- return true;
- }
-
- /*!
- @brief Parses a zero-terminated string of length @a len from the BSON
- input.
- @param[in] len The length (including the zero-byte at the end) of the
- string to be read.
- @param[in, out] result A reference to the string variable where the read
- string is to be stored.
- @tparam NumberType The type of the length @a len
- @pre len >= 1
- @return `true` if the string was successfully parsed
- */
- template<typename NumberType>
- bool get_bson_string(const NumberType len, string_t& result)
- {
- if (JSON_HEDLEY_UNLIKELY(len < 1))
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string")));
- }
-
- return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) and get() != std::char_traits<char_type>::eof();
- }
-
- /*!
- @brief Parses a byte array input of length @a len from the BSON input.
- @param[in] len The length of the byte array to be read.
- @param[in, out] result A reference to the binary variable where the read
- array is to be stored.
- @tparam NumberType The type of the length @a len
- @pre len >= 0
- @return `true` if the byte array was successfully parsed
- */
- template<typename NumberType>
- bool get_bson_binary(const NumberType len, binary_t& result)
- {
- if (JSON_HEDLEY_UNLIKELY(len < 0))
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary")));
- }
-
- // All BSON binary values have a subtype
- std::uint8_t subtype;
- get_number<std::uint8_t>(input_format_t::bson, subtype);
- result.set_subtype(subtype);
-
- return get_binary(input_format_t::bson, len, result);
- }
-
- /*!
- @brief Read a BSON document element of the given @a element_type.
- @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
- @param[in] element_type_parse_position The position in the input stream,
- where the `element_type` was read.
- @warning Not all BSON element types are supported yet. An unsupported
- @a element_type will give rise to a parse_error.114:
- Unsupported BSON record type 0x...
- @return whether a valid BSON-object/array was passed to the SAX parser
- */
- bool parse_bson_element_internal(const char_int_type element_type,
- const std::size_t element_type_parse_position)
- {
- switch (element_type)
- {
- case 0x01: // double
- {
- double number;
- return get_number<double, true>(input_format_t::bson, number) and sax->number_float(static_cast<number_float_t>(number), "");
- }
-
- case 0x02: // string
- {
- std::int32_t len;
- string_t value;
- return get_number<std::int32_t, true>(input_format_t::bson, len) and get_bson_string(len, value) and sax->string(value);
- }
-
- case 0x03: // object
- {
- return parse_bson_internal();
- }
-
- case 0x04: // array
- {
- return parse_bson_array();
- }
-
- case 0x05: // binary
- {
- std::int32_t len;
- binary_t value;
- return get_number<std::int32_t, true>(input_format_t::bson, len) and get_bson_binary(len, value) and sax->binary(value);
- }
-
- case 0x08: // boolean
- {
- return sax->boolean(get() != 0);
- }
-
- case 0x0A: // null
- {
- return sax->null();
- }
-
- case 0x10: // int32
- {
- std::int32_t value;
- return get_number<std::int32_t, true>(input_format_t::bson, value) and sax->number_integer(value);
- }
-
- case 0x12: // int64
- {
- std::int64_t value;
- return get_number<std::int64_t, true>(input_format_t::bson, value) and sax->number_integer(value);
- }
-
- default: // anything else not supported (yet)
- {
- std::array<char, 3> cr{{}};
- (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type));
- return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data())));
- }
- }
- }
-
- /*!
- @brief Read a BSON element list (as specified in the BSON-spec)
-
- The same binary layout is used for objects and arrays, hence it must be
- indicated with the argument @a is_array which one is expected
- (true --> array, false --> object).
-
- @param[in] is_array Determines if the element list being read is to be
- treated as an object (@a is_array == false), or as an
- array (@a is_array == true).
- @return whether a valid BSON-object/array was passed to the SAX parser
- */
- bool parse_bson_element_list(const bool is_array)
- {
- string_t key;
-
- while (auto element_type = get())
- {
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list")))
- {
- return false;
- }
-
- const std::size_t element_type_parse_position = chars_read;
- if (JSON_HEDLEY_UNLIKELY(not get_bson_cstr(key)))
- {
- return false;
- }
-
- if (not is_array and not sax->key(key))
- {
- return false;
- }
-
- if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))
- {
- return false;
- }
-
- // get_bson_cstr only appends
- key.clear();
- }
-
- return true;
- }
-
- /*!
- @brief Reads an array from the BSON input and passes it to the SAX-parser.
- @return whether a valid BSON-array was passed to the SAX parser
- */
- bool parse_bson_array()
- {
- std::int32_t document_size;
- get_number<std::int32_t, true>(input_format_t::bson, document_size);
-
- if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
- {
- return false;
- }
-
- if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/true)))
- {
- return false;
- }
-
- return sax->end_array();
- }
-
- //////////
- // CBOR //
- //////////
-
- /*!
- @param[in] get_char whether a new character should be retrieved from the
- input (true, default) or whether the last read
- character should be considered instead
-
- @return whether a valid CBOR value was passed to the SAX parser
- */
- bool parse_cbor_internal(const bool get_char = true)
- {
- switch (get_char ? get() : current)
- {
- // EOF
- case std::char_traits<char_type>::eof():
- return unexpect_eof(input_format_t::cbor, "value");
-
- // Integer 0x00..0x17 (0..23)
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x08:
- case 0x09:
- case 0x0A:
- case 0x0B:
- case 0x0C:
- case 0x0D:
- case 0x0E:
- case 0x0F:
- case 0x10:
- case 0x11:
- case 0x12:
- case 0x13:
- case 0x14:
- case 0x15:
- case 0x16:
- case 0x17:
- return sax->number_unsigned(static_cast<number_unsigned_t>(current));
-
- case 0x18: // Unsigned integer (one-byte uint8_t follows)
- {
- std::uint8_t number;
- return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
- }
-
- case 0x19: // Unsigned integer (two-byte uint16_t follows)
- {
- std::uint16_t number;
- return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
- }
-
- case 0x1A: // Unsigned integer (four-byte uint32_t follows)
- {
- std::uint32_t number;
- return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
- }
-
- case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
- {
- std::uint64_t number;
- return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
- }
-
- // Negative integer -1-0x00..-1-0x17 (-1..-24)
- case 0x20:
- case 0x21:
- case 0x22:
- case 0x23:
- case 0x24:
- case 0x25:
- case 0x26:
- case 0x27:
- case 0x28:
- case 0x29:
- case 0x2A:
- case 0x2B:
- case 0x2C:
- case 0x2D:
- case 0x2E:
- case 0x2F:
- case 0x30:
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
-
- case 0x38: // Negative integer (one-byte uint8_t follows)
- {
- std::uint8_t number;
- return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
- }
-
- case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
- {
- std::uint16_t number;
- return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
- }
-
- case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
- {
- std::uint32_t number;
- return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
- }
-
- case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
- {
- std::uint64_t number;
- return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)
- - static_cast<number_integer_t>(number));
- }
-
- // Binary data (0x00..0x17 bytes follow)
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x44:
- case 0x45:
- case 0x46:
- case 0x47:
- case 0x48:
- case 0x49:
- case 0x4A:
- case 0x4B:
- case 0x4C:
- case 0x4D:
- case 0x4E:
- case 0x4F:
- case 0x50:
- case 0x51:
- case 0x52:
- case 0x53:
- case 0x54:
- case 0x55:
- case 0x56:
- case 0x57:
- case 0x58: // Binary data (one-byte uint8_t for n follows)
- case 0x59: // Binary data (two-byte uint16_t for n follow)
- case 0x5A: // Binary data (four-byte uint32_t for n follow)
- case 0x5B: // Binary data (eight-byte uint64_t for n follow)
- case 0x5F: // Binary data (indefinite length)
- {
- binary_t b;
- return get_cbor_binary(b) and sax->binary(b);
- }
-
- // UTF-8 string (0x00..0x17 bytes follow)
- case 0x60:
- case 0x61:
- case 0x62:
- case 0x63:
- case 0x64:
- case 0x65:
- case 0x66:
- case 0x67:
- case 0x68:
- case 0x69:
- case 0x6A:
- case 0x6B:
- case 0x6C:
- case 0x6D:
- case 0x6E:
- case 0x6F:
- case 0x70:
- case 0x71:
- case 0x72:
- case 0x73:
- case 0x74:
- case 0x75:
- case 0x76:
- case 0x77:
- case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
- case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
- case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
- case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
- case 0x7F: // UTF-8 string (indefinite length)
- {
- string_t s;
- return get_cbor_string(s) and sax->string(s);
- }
-
- // array (0x00..0x17 data items follow)
- case 0x80:
- case 0x81:
- case 0x82:
- case 0x83:
- case 0x84:
- case 0x85:
- case 0x86:
- case 0x87:
- case 0x88:
- case 0x89:
- case 0x8A:
- case 0x8B:
- case 0x8C:
- case 0x8D:
- case 0x8E:
- case 0x8F:
- case 0x90:
- case 0x91:
- case 0x92:
- case 0x93:
- case 0x94:
- case 0x95:
- case 0x96:
- case 0x97:
- return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
-
- case 0x98: // array (one-byte uint8_t for n follows)
- {
- std::uint8_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
- }
-
- case 0x99: // array (two-byte uint16_t for n follow)
- {
- std::uint16_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
- }
-
- case 0x9A: // array (four-byte uint32_t for n follow)
- {
- std::uint32_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
- }
-
- case 0x9B: // array (eight-byte uint64_t for n follow)
- {
- std::uint64_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
- }
-
- case 0x9F: // array (indefinite length)
- return get_cbor_array(std::size_t(-1));
-
- // map (0x00..0x17 pairs of data items follow)
- case 0xA0:
- case 0xA1:
- case 0xA2:
- case 0xA3:
- case 0xA4:
- case 0xA5:
- case 0xA6:
- case 0xA7:
- case 0xA8:
- case 0xA9:
- case 0xAA:
- case 0xAB:
- case 0xAC:
- case 0xAD:
- case 0xAE:
- case 0xAF:
- case 0xB0:
- case 0xB1:
- case 0xB2:
- case 0xB3:
- case 0xB4:
- case 0xB5:
- case 0xB6:
- case 0xB7:
- return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
-
- case 0xB8: // map (one-byte uint8_t for n follows)
- {
- std::uint8_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
- }
-
- case 0xB9: // map (two-byte uint16_t for n follow)
- {
- std::uint16_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
- }
-
- case 0xBA: // map (four-byte uint32_t for n follow)
- {
- std::uint32_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
- }
-
- case 0xBB: // map (eight-byte uint64_t for n follow)
- {
- std::uint64_t len;
- return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
- }
-
- case 0xBF: // map (indefinite length)
- return get_cbor_object(std::size_t(-1));
-
- case 0xF4: // false
- return sax->boolean(false);
-
- case 0xF5: // true
- return sax->boolean(true);
-
- case 0xF6: // null
- return sax->null();
-
- case 0xF9: // Half-Precision Float (two-byte IEEE 754)
- {
- const auto byte1_raw = get();
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
- {
- return false;
- }
- const auto byte2_raw = get();
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
- {
- return false;
- }
-
- const auto byte1 = static_cast<unsigned char>(byte1_raw);
- const auto byte2 = static_cast<unsigned char>(byte2_raw);
-
- // code from RFC 7049, Appendix D, Figure 3:
- // As half-precision floating-point numbers were only added
- // to IEEE 754 in 2008, today's programming platforms often
- // still only have limited support for them. It is very
- // easy to include at least decoding support for them even
- // without such support. An example of a small decoder for
- // half-precision floating-point numbers in the C language
- // is shown in Fig. 3.
- const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
- const double val = [&half]
- {
- const int exp = (half >> 10u) & 0x1Fu;
- const unsigned int mant = half & 0x3FFu;
- assert(0 <= exp and exp <= 32);
- assert(mant <= 1024);
- switch (exp)
- {
- case 0:
- return std::ldexp(mant, -24);
- case 31:
- return (mant == 0)
- ? std::numeric_limits<double>::infinity()
- : std::numeric_limits<double>::quiet_NaN();
- default:
- return std::ldexp(mant + 1024, exp - 25);
- }
- }();
- return sax->number_float((half & 0x8000u) != 0
- ? static_cast<number_float_t>(-val)
- : static_cast<number_float_t>(val), "");
- }
-
- case 0xFA: // Single-Precision Float (four-byte IEEE 754)
- {
- float number;
- return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), "");
- }
-
- case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
- {
- double number;
- return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), "");
- }
-
- default: // anything else (0xFF is handled inside the other types)
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value")));
- }
- }
- }
-
- /*!
- @brief reads a CBOR string
-
- This function first reads starting bytes to determine the expected
- string length and then copies this number of bytes into a string.
- Additionally, CBOR's strings with indefinite lengths are supported.
-
- @param[out] result created string
-
- @return whether string creation completed
- */
- bool get_cbor_string(string_t& result)
- {
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string")))
- {
- return false;
- }
-
- switch (current)
- {
- // UTF-8 string (0x00..0x17 bytes follow)
- case 0x60:
- case 0x61:
- case 0x62:
- case 0x63:
- case 0x64:
- case 0x65:
- case 0x66:
- case 0x67:
- case 0x68:
- case 0x69:
- case 0x6A:
- case 0x6B:
- case 0x6C:
- case 0x6D:
- case 0x6E:
- case 0x6F:
- case 0x70:
- case 0x71:
- case 0x72:
- case 0x73:
- case 0x74:
- case 0x75:
- case 0x76:
- case 0x77:
- {
- return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
- }
-
- case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
- {
- std::uint8_t len;
- return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
- }
-
- case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
- {
- std::uint16_t len;
- return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
- }
-
- case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
- {
- std::uint32_t len;
- return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
- }
-
- case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
- {
- std::uint64_t len;
- return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
- }
-
- case 0x7F: // UTF-8 string (indefinite length)
- {
- while (get() != 0xFF)
- {
- string_t chunk;
- if (not get_cbor_string(chunk))
- {
- return false;
- }
- result.append(chunk);
- }
- return true;
- }
-
- default:
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string")));
- }
- }
- }
-
- /*!
- @brief reads a CBOR byte array
-
- This function first reads starting bytes to determine the expected
- byte array length and then copies this number of bytes into the byte array.
- Additionally, CBOR's byte arrays with indefinite lengths are supported.
-
- @param[out] result created byte array
-
- @return whether byte array creation completed
- */
- bool get_cbor_binary(binary_t& result)
- {
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "binary")))
- {
- return false;
- }
-
- switch (current)
- {
- // Binary data (0x00..0x17 bytes follow)
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x44:
- case 0x45:
- case 0x46:
- case 0x47:
- case 0x48:
- case 0x49:
- case 0x4A:
- case 0x4B:
- case 0x4C:
- case 0x4D:
- case 0x4E:
- case 0x4F:
- case 0x50:
- case 0x51:
- case 0x52:
- case 0x53:
- case 0x54:
- case 0x55:
- case 0x56:
- case 0x57:
- {
- return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
- }
-
- case 0x58: // Binary data (one-byte uint8_t for n follows)
- {
- std::uint8_t len;
- return get_number(input_format_t::cbor, len) and
- get_binary(input_format_t::cbor, len, result);
- }
-
- case 0x59: // Binary data (two-byte uint16_t for n follow)
- {
- std::uint16_t len;
- return get_number(input_format_t::cbor, len) and
- get_binary(input_format_t::cbor, len, result);
- }
-
- case 0x5A: // Binary data (four-byte uint32_t for n follow)
- {
- std::uint32_t len;
- return get_number(input_format_t::cbor, len) and
- get_binary(input_format_t::cbor, len, result);
- }
-
- case 0x5B: // Binary data (eight-byte uint64_t for n follow)
- {
- std::uint64_t len;
- return get_number(input_format_t::cbor, len) and
- get_binary(input_format_t::cbor, len, result);
- }
-
- case 0x5F: // Binary data (indefinite length)
- {
- while (get() != 0xFF)
- {
- binary_t chunk;
- if (not get_cbor_binary(chunk))
- {
- return false;
- }
- result.insert(result.end(), chunk.begin(), chunk.end());
- }
- return true;
- }
-
- default:
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary")));
- }
- }
- }
-
- /*!
- @param[in] len the length of the array or std::size_t(-1) for an
- array of indefinite size
- @return whether array creation completed
- */
- bool get_cbor_array(const std::size_t len)
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len)))
- {
- return false;
- }
-
- if (len != std::size_t(-1))
- {
- for (std::size_t i = 0; i < len; ++i)
- {
- if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
- {
- return false;
- }
- }
- }
- else
- {
- while (get() != 0xFF)
- {
- if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal(false)))
- {
- return false;
- }
- }
- }
-
- return sax->end_array();
- }
-
- /*!
- @param[in] len the length of the object or std::size_t(-1) for an
- object of indefinite size
- @return whether object creation completed
- */
- bool get_cbor_object(const std::size_t len)
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len)))
- {
- return false;
- }
-
- string_t key;
- if (len != std::size_t(-1))
- {
- for (std::size_t i = 0; i < len; ++i)
- {
- get();
- if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
- {
- return false;
- }
-
- if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
- {
- return false;
- }
- key.clear();
- }
- }
- else
- {
- while (get() != 0xFF)
- {
- if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
- {
- return false;
- }
-
- if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
- {
- return false;
- }
- key.clear();
- }
- }
-
- return sax->end_object();
- }
-
- /////////////
- // MsgPack //
- /////////////
-
- /*!
- @return whether a valid MessagePack value was passed to the SAX parser
- */
- bool parse_msgpack_internal()
- {
- switch (get())
- {
- // EOF
- case std::char_traits<char_type>::eof():
- return unexpect_eof(input_format_t::msgpack, "value");
-
- // positive fixint
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x08:
- case 0x09:
- case 0x0A:
- case 0x0B:
- case 0x0C:
- case 0x0D:
- case 0x0E:
- case 0x0F:
- case 0x10:
- case 0x11:
- case 0x12:
- case 0x13:
- case 0x14:
- case 0x15:
- case 0x16:
- case 0x17:
- case 0x18:
- case 0x19:
- case 0x1A:
- case 0x1B:
- case 0x1C:
- case 0x1D:
- case 0x1E:
- case 0x1F:
- case 0x20:
- case 0x21:
- case 0x22:
- case 0x23:
- case 0x24:
- case 0x25:
- case 0x26:
- case 0x27:
- case 0x28:
- case 0x29:
- case 0x2A:
- case 0x2B:
- case 0x2C:
- case 0x2D:
- case 0x2E:
- case 0x2F:
- case 0x30:
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- case 0x38:
- case 0x39:
- case 0x3A:
- case 0x3B:
- case 0x3C:
- case 0x3D:
- case 0x3E:
- case 0x3F:
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x44:
- case 0x45:
- case 0x46:
- case 0x47:
- case 0x48:
- case 0x49:
- case 0x4A:
- case 0x4B:
- case 0x4C:
- case 0x4D:
- case 0x4E:
- case 0x4F:
- case 0x50:
- case 0x51:
- case 0x52:
- case 0x53:
- case 0x54:
- case 0x55:
- case 0x56:
- case 0x57:
- case 0x58:
- case 0x59:
- case 0x5A:
- case 0x5B:
- case 0x5C:
- case 0x5D:
- case 0x5E:
- case 0x5F:
- case 0x60:
- case 0x61:
- case 0x62:
- case 0x63:
- case 0x64:
- case 0x65:
- case 0x66:
- case 0x67:
- case 0x68:
- case 0x69:
- case 0x6A:
- case 0x6B:
- case 0x6C:
- case 0x6D:
- case 0x6E:
- case 0x6F:
- case 0x70:
- case 0x71:
- case 0x72:
- case 0x73:
- case 0x74:
- case 0x75:
- case 0x76:
- case 0x77:
- case 0x78:
- case 0x79:
- case 0x7A:
- case 0x7B:
- case 0x7C:
- case 0x7D:
- case 0x7E:
- case 0x7F:
- return sax->number_unsigned(static_cast<number_unsigned_t>(current));
-
- // fixmap
- case 0x80:
- case 0x81:
- case 0x82:
- case 0x83:
- case 0x84:
- case 0x85:
- case 0x86:
- case 0x87:
- case 0x88:
- case 0x89:
- case 0x8A:
- case 0x8B:
- case 0x8C:
- case 0x8D:
- case 0x8E:
- case 0x8F:
- return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
-
- // fixarray
- case 0x90:
- case 0x91:
- case 0x92:
- case 0x93:
- case 0x94:
- case 0x95:
- case 0x96:
- case 0x97:
- case 0x98:
- case 0x99:
- case 0x9A:
- case 0x9B:
- case 0x9C:
- case 0x9D:
- case 0x9E:
- case 0x9F:
- return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
-
- // fixstr
- case 0xA0:
- case 0xA1:
- case 0xA2:
- case 0xA3:
- case 0xA4:
- case 0xA5:
- case 0xA6:
- case 0xA7:
- case 0xA8:
- case 0xA9:
- case 0xAA:
- case 0xAB:
- case 0xAC:
- case 0xAD:
- case 0xAE:
- case 0xAF:
- case 0xB0:
- case 0xB1:
- case 0xB2:
- case 0xB3:
- case 0xB4:
- case 0xB5:
- case 0xB6:
- case 0xB7:
- case 0xB8:
- case 0xB9:
- case 0xBA:
- case 0xBB:
- case 0xBC:
- case 0xBD:
- case 0xBE:
- case 0xBF:
- case 0xD9: // str 8
- case 0xDA: // str 16
- case 0xDB: // str 32
- {
- string_t s;
- return get_msgpack_string(s) and sax->string(s);
- }
-
- case 0xC0: // nil
- return sax->null();
-
- case 0xC2: // false
- return sax->boolean(false);
-
- case 0xC3: // true
- return sax->boolean(true);
-
- case 0xC4: // bin 8
- case 0xC5: // bin 16
- case 0xC6: // bin 32
- case 0xC7: // ext 8
- case 0xC8: // ext 16
- case 0xC9: // ext 32
- case 0xD4: // fixext 1
- case 0xD5: // fixext 2
- case 0xD6: // fixext 4
- case 0xD7: // fixext 8
- case 0xD8: // fixext 16
- {
- binary_t b;
- return get_msgpack_binary(b) and sax->binary(b);
- }
-
- case 0xCA: // float 32
- {
- float number;
- return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), "");
- }
-
- case 0xCB: // float 64
- {
- double number;
- return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), "");
- }
-
- case 0xCC: // uint 8
- {
- std::uint8_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
- }
-
- case 0xCD: // uint 16
- {
- std::uint16_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
- }
-
- case 0xCE: // uint 32
- {
- std::uint32_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
- }
-
- case 0xCF: // uint 64
- {
- std::uint64_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
- }
-
- case 0xD0: // int 8
- {
- std::int8_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
- }
-
- case 0xD1: // int 16
- {
- std::int16_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
- }
-
- case 0xD2: // int 32
- {
- std::int32_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
- }
-
- case 0xD3: // int 64
- {
- std::int64_t number;
- return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
- }
-
- case 0xDC: // array 16
- {
- std::uint16_t len;
- return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
- }
-
- case 0xDD: // array 32
- {
- std::uint32_t len;
- return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
- }
-
- case 0xDE: // map 16
- {
- std::uint16_t len;
- return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
- }
-
- case 0xDF: // map 32
- {
- std::uint32_t len;
- return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
- }
-
- // negative fixint
- case 0xE0:
- case 0xE1:
- case 0xE2:
- case 0xE3:
- case 0xE4:
- case 0xE5:
- case 0xE6:
- case 0xE7:
- case 0xE8:
- case 0xE9:
- case 0xEA:
- case 0xEB:
- case 0xEC:
- case 0xED:
- case 0xEE:
- case 0xEF:
- case 0xF0:
- case 0xF1:
- case 0xF2:
- case 0xF3:
- case 0xF4:
- case 0xF5:
- case 0xF6:
- case 0xF7:
- case 0xF8:
- case 0xF9:
- case 0xFA:
- case 0xFB:
- case 0xFC:
- case 0xFD:
- case 0xFE:
- case 0xFF:
- return sax->number_integer(static_cast<std::int8_t>(current));
-
- default: // anything else
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value")));
- }
- }
- }
-
- /*!
- @brief reads a MessagePack string
-
- This function first reads starting bytes to determine the expected
- string length and then copies this number of bytes into a string.
-
- @param[out] result created string
-
- @return whether string creation completed
- */
- bool get_msgpack_string(string_t& result)
- {
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string")))
- {
- return false;
- }
-
- switch (current)
- {
- // fixstr
- case 0xA0:
- case 0xA1:
- case 0xA2:
- case 0xA3:
- case 0xA4:
- case 0xA5:
- case 0xA6:
- case 0xA7:
- case 0xA8:
- case 0xA9:
- case 0xAA:
- case 0xAB:
- case 0xAC:
- case 0xAD:
- case 0xAE:
- case 0xAF:
- case 0xB0:
- case 0xB1:
- case 0xB2:
- case 0xB3:
- case 0xB4:
- case 0xB5:
- case 0xB6:
- case 0xB7:
- case 0xB8:
- case 0xB9:
- case 0xBA:
- case 0xBB:
- case 0xBC:
- case 0xBD:
- case 0xBE:
- case 0xBF:
- {
- return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
- }
-
- case 0xD9: // str 8
- {
- std::uint8_t len;
- return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
- }
-
- case 0xDA: // str 16
- {
- std::uint16_t len;
- return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
- }
-
- case 0xDB: // str 32
- {
- std::uint32_t len;
- return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
- }
-
- default:
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string")));
- }
- }
- }
-
- /*!
- @brief reads a MessagePack byte array
-
- This function first reads starting bytes to determine the expected
- byte array length and then copies this number of bytes into a byte array.
-
- @param[out] result created byte array
-
- @return whether byte array creation completed
- */
- bool get_msgpack_binary(binary_t& result)
- {
- // helper function to set the subtype
- auto assign_and_return_true = [&result](std::int8_t subtype)
- {
- result.set_subtype(static_cast<std::uint8_t>(subtype));
- return true;
- };
-
- switch (current)
- {
- case 0xC4: // bin 8
- {
- std::uint8_t len;
- return get_number(input_format_t::msgpack, len) and
- get_binary(input_format_t::msgpack, len, result);
- }
-
- case 0xC5: // bin 16
- {
- std::uint16_t len;
- return get_number(input_format_t::msgpack, len) and
- get_binary(input_format_t::msgpack, len, result);
- }
-
- case 0xC6: // bin 32
- {
- std::uint32_t len;
- return get_number(input_format_t::msgpack, len) and
- get_binary(input_format_t::msgpack, len, result);
- }
-
- case 0xC7: // ext 8
- {
- std::uint8_t len;
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, len) and
- get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, len, result) and
- assign_and_return_true(subtype);
- }
-
- case 0xC8: // ext 16
- {
- std::uint16_t len;
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, len) and
- get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, len, result) and
- assign_and_return_true(subtype);
- }
-
- case 0xC9: // ext 32
- {
- std::uint32_t len;
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, len) and
- get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, len, result) and
- assign_and_return_true(subtype);
- }
-
- case 0xD4: // fixext 1
- {
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, 1, result) and
- assign_and_return_true(subtype);
- }
-
- case 0xD5: // fixext 2
- {
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, 2, result) and
- assign_and_return_true(subtype);
- }
-
- case 0xD6: // fixext 4
- {
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, 4, result) and
- assign_and_return_true(subtype);
- }
-
- case 0xD7: // fixext 8
- {
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, 8, result) and
- assign_and_return_true(subtype);
- }
-
- case 0xD8: // fixext 16
- {
- std::int8_t subtype;
- return get_number(input_format_t::msgpack, subtype) and
- get_binary(input_format_t::msgpack, 16, result) and
- assign_and_return_true(subtype);
- }
-
- default: // LCOV_EXCL_LINE
- return false; // LCOV_EXCL_LINE
- }
- }
-
- /*!
- @param[in] len the length of the array
- @return whether array creation completed
- */
- bool get_msgpack_array(const std::size_t len)
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len)))
- {
- return false;
- }
-
- for (std::size_t i = 0; i < len; ++i)
- {
- if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal()))
- {
- return false;
- }
- }
-
- return sax->end_array();
- }
-
- /*!
- @param[in] len the length of the object
- @return whether object creation completed
- */
- bool get_msgpack_object(const std::size_t len)
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len)))
- {
- return false;
- }
-
- string_t key;
- for (std::size_t i = 0; i < len; ++i)
- {
- get();
- if (JSON_HEDLEY_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))
- {
- return false;
- }
-
- if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal()))
- {
- return false;
- }
- key.clear();
- }
-
- return sax->end_object();
- }
-
- ////////////
- // UBJSON //
- ////////////
-
- /*!
- @param[in] get_char whether a new character should be retrieved from the
- input (true, default) or whether the last read
- character should be considered instead
-
- @return whether a valid UBJSON value was passed to the SAX parser
- */
- bool parse_ubjson_internal(const bool get_char = true)
- {
- return get_ubjson_value(get_char ? get_ignore_noop() : current);
- }
-
- /*!
- @brief reads a UBJSON string
-
- This function is either called after reading the 'S' byte explicitly
- indicating a string, or in case of an object key where the 'S' byte can be
- left out.
-
- @param[out] result created string
- @param[in] get_char whether a new character should be retrieved from the
- input (true, default) or whether the last read
- character should be considered instead
-
- @return whether string creation completed
- */
- bool get_ubjson_string(string_t& result, const bool get_char = true)
- {
- if (get_char)
- {
- get(); // TODO(niels): may we ignore N here?
- }
-
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
- {
- return false;
- }
-
- switch (current)
- {
- case 'U':
- {
- std::uint8_t len;
- return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
- }
-
- case 'i':
- {
- std::int8_t len;
- return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
- }
-
- case 'I':
- {
- std::int16_t len;
- return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
- }
-
- case 'l':
- {
- std::int32_t len;
- return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
- }
-
- case 'L':
- {
- std::int64_t len;
- return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
- }
-
- default:
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string")));
- }
- }
-
- /*!
- @param[out] result determined size
- @return whether size determination completed
- */
- bool get_ubjson_size_value(std::size_t& result)
- {
- switch (get_ignore_noop())
- {
- case 'U':
- {
- std::uint8_t number;
- if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
- {
- return false;
- }
- result = static_cast<std::size_t>(number);
- return true;
- }
-
- case 'i':
- {
- std::int8_t number;
- if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
- {
- return false;
- }
- result = static_cast<std::size_t>(number);
- return true;
- }
-
- case 'I':
- {
- std::int16_t number;
- if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
- {
- return false;
- }
- result = static_cast<std::size_t>(number);
- return true;
- }
-
- case 'l':
- {
- std::int32_t number;
- if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
- {
- return false;
- }
- result = static_cast<std::size_t>(number);
- return true;
- }
-
- case 'L':
- {
- std::int64_t number;
- if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
- {
- return false;
- }
- result = static_cast<std::size_t>(number);
- return true;
- }
-
- default:
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size")));
- }
- }
- }
-
- /*!
- @brief determine the type and size for a container
-
- In the optimized UBJSON format, a type and a size can be provided to allow
- for a more compact representation.
-
- @param[out] result pair of the size and the type
-
- @return whether pair creation completed
- */
- bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result)
- {
- result.first = string_t::npos; // size
- result.second = 0; // type
-
- get_ignore_noop();
-
- if (current == '$')
- {
- result.second = get(); // must not ignore 'N', because 'N' maybe the type
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type")))
- {
- return false;
- }
-
- get_ignore_noop();
- if (JSON_HEDLEY_UNLIKELY(current != '#'))
- {
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
- {
- return false;
- }
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size")));
- }
-
- return get_ubjson_size_value(result.first);
- }
-
- if (current == '#')
- {
- return get_ubjson_size_value(result.first);
- }
-
- return true;
- }
-
- /*!
- @param prefix the previously read or set type prefix
- @return whether value creation completed
- */
- bool get_ubjson_value(const char_int_type prefix)
- {
- switch (prefix)
- {
- case std::char_traits<char_type>::eof(): // EOF
- return unexpect_eof(input_format_t::ubjson, "value");
-
- case 'T': // true
- return sax->boolean(true);
- case 'F': // false
- return sax->boolean(false);
-
- case 'Z': // null
- return sax->null();
-
- case 'U':
- {
- std::uint8_t number;
- return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);
- }
-
- case 'i':
- {
- std::int8_t number;
- return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
- }
-
- case 'I':
- {
- std::int16_t number;
- return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
- }
-
- case 'l':
- {
- std::int32_t number;
- return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
- }
-
- case 'L':
- {
- std::int64_t number;
- return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
- }
-
- case 'd':
- {
- float number;
- return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), "");
- }
-
- case 'D':
- {
- double number;
- return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), "");
- }
-
- case 'C': // char
- {
- get();
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char")))
- {
- return false;
- }
- if (JSON_HEDLEY_UNLIKELY(current > 127))
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char")));
- }
- string_t s(1, static_cast<typename string_t::value_type>(current));
- return sax->string(s);
- }
-
- case 'S': // string
- {
- string_t s;
- return get_ubjson_string(s) and sax->string(s);
- }
-
- case '[': // array
- return get_ubjson_array();
-
- case '{': // object
- return get_ubjson_object();
-
- default: // anything else
- {
- auto last_token = get_token_string();
- return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value")));
- }
- }
- }
-
- /*!
- @return whether array creation completed
- */
- bool get_ubjson_array()
- {
- std::pair<std::size_t, char_int_type> size_and_type;
- if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type)))
- {
- return false;
- }
-
- if (size_and_type.first != string_t::npos)
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_array(size_and_type.first)))
- {
- return false;
- }
-
- if (size_and_type.second != 0)
- {
- if (size_and_type.second != 'N')
- {
- for (std::size_t i = 0; i < size_and_type.first; ++i)
- {
- if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second)))
- {
- return false;
- }
- }
- }
- }
- else
- {
- for (std::size_t i = 0; i < size_and_type.first; ++i)
- {
- if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
- {
- return false;
- }
- }
- }
- }
- else
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
- {
- return false;
- }
-
- while (current != ']')
- {
- if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal(false)))
- {
- return false;
- }
- get_ignore_noop();
- }
- }
-
- return sax->end_array();
- }
-
- /*!
- @return whether object creation completed
- */
- bool get_ubjson_object()
- {
- std::pair<std::size_t, char_int_type> size_and_type;
- if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type)))
- {
- return false;
- }
-
- string_t key;
- if (size_and_type.first != string_t::npos)
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_object(size_and_type.first)))
- {
- return false;
- }
-
- if (size_and_type.second != 0)
- {
- for (std::size_t i = 0; i < size_and_type.first; ++i)
- {
- if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
- {
- return false;
- }
- if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second)))
- {
- return false;
- }
- key.clear();
- }
- }
- else
- {
- for (std::size_t i = 0; i < size_and_type.first; ++i)
- {
- if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
- {
- return false;
- }
- if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
- {
- return false;
- }
- key.clear();
- }
- }
- }
- else
- {
- if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
- {
- return false;
- }
-
- while (current != '}')
- {
- if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))
- {
- return false;
- }
- if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
- {
- return false;
- }
- get_ignore_noop();
- key.clear();
- }
- }
-
- return sax->end_object();
- }
-
- // Note, no reader for UBJSON binary types is implemented because they do
- // not exist
-
- ///////////////////////
- // Utility functions //
- ///////////////////////
-
- /*!
- @brief get next character from the input
-
- This function provides the interface to the used input adapter. It does
- not throw in case the input reached EOF, but returns a -'ve valued
- `std::char_traits<char_type>::eof()` in that case.
-
- @return character read from the input
- */
- char_int_type get()
- {
- ++chars_read;
- return current = ia.get_character();
- }
-
- /*!
- @return character read from the input after ignoring all 'N' entries
- */
- char_int_type get_ignore_noop()
- {
- do
- {
- get();
- }
- while (current == 'N');
-
- return current;
- }
-
- /*
- @brief read a number from the input
-
- @tparam NumberType the type of the number
- @param[in] format the current format (for diagnostics)
- @param[out] result number of type @a NumberType
-
- @return whether conversion completed
-
- @note This function needs to respect the system's endianess, because
- bytes in CBOR, MessagePack, and UBJSON are stored in network order
- (big endian) and therefore need reordering on little endian systems.
- */
- template<typename NumberType, bool InputIsLittleEndian = false>
- bool get_number(const input_format_t format, NumberType& result)
- {
- // step 1: read input into array with system's byte order
- std::array<std::uint8_t, sizeof(NumberType)> vec;
- for (std::size_t i = 0; i < sizeof(NumberType); ++i)
- {
- get();
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "number")))
- {
- return false;
- }
-
- // reverse byte order prior to conversion if necessary
- if (is_little_endian != InputIsLittleEndian)
- {
- vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
- }
- else
- {
- vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
- }
- }
-
- // step 2: convert array into number of type T and return
- std::memcpy(&result, vec.data(), sizeof(NumberType));
- return true;
- }
-
- /*!
- @brief create a string by reading characters from the input
-
- @tparam NumberType the type of the number
- @param[in] format the current format (for diagnostics)
- @param[in] len number of characters to read
- @param[out] result string created by reading @a len bytes
-
- @return whether string creation completed
-
- @note We can not reserve @a len bytes for the result, because @a len
- may be too large. Usually, @ref unexpect_eof() detects the end of
- the input before we run out of string memory.
- */
- template<typename NumberType>
- bool get_string(const input_format_t format,
- const NumberType len,
- string_t& result)
- {
- bool success = true;
- std::generate_n(std::back_inserter(result), len, [this, &success, &format]()
- {
- get();
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "string")))
- {
- success = false;
- }
- return std::char_traits<char_type>::to_char_type(current);
- });
- return success;
- }
-
- /*!
- @brief create a byte array by reading bytes from the input
-
- @tparam NumberType the type of the number
- @param[in] format the current format (for diagnostics)
- @param[in] len number of bytes to read
- @param[out] result byte array created by reading @a len bytes
-
- @return whether byte array creation completed
-
- @note We can not reserve @a len bytes for the result, because @a len
- may be too large. Usually, @ref unexpect_eof() detects the end of
- the input before we run out of memory.
- */
- template<typename NumberType>
- bool get_binary(const input_format_t format,
- const NumberType len,
- binary_t& result)
- {
- bool success = true;
- std::generate_n(std::back_inserter(result), len, [this, &success, &format]()
- {
- get();
- if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "binary")))
- {
- success = false;
- }
- return static_cast<std::uint8_t>(current);
- });
- return success;
- }
-
- /*!
- @param[in] format the current format (for diagnostics)
- @param[in] context further context information (for diagnostics)
- @return whether the last read character is not EOF
- */
- JSON_HEDLEY_NON_NULL(3)
- bool unexpect_eof(const input_format_t format, const char* context) const
- {
- if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
- {
- return sax->parse_error(chars_read, "<end of file>",
- parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context)));
- }
- return true;
- }
-
- /*!
- @return a string representation of the last read byte
- */
- std::string get_token_string() const
- {
- std::array<char, 3> cr{{}};
- (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current));
- return std::string{cr.data()};
- }
-
- /*!
- @param[in] format the current format
- @param[in] detail a detailed error message
- @param[in] context further context information
- @return a message string to use in the parse_error exceptions
- */
- std::string exception_message(const input_format_t format,
- const std::string& detail,
- const std::string& context) const
- {
- std::string error_msg = "syntax error while parsing ";
-
- switch (format)
- {
- case input_format_t::cbor:
- error_msg += "CBOR";
- break;
-
- case input_format_t::msgpack:
- error_msg += "MessagePack";
- break;
-
- case input_format_t::ubjson:
- error_msg += "UBJSON";
- break;
-
- case input_format_t::bson:
- error_msg += "BSON";
- break;
-
- default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
- }
-
- return error_msg + " " + context + ": " + detail;
- }
-
- private:
- /// input adapter
- InputAdapterType ia;
-
- /// the current character
- char_int_type current = std::char_traits<char_type>::eof();
-
- /// the number of characters read
- std::size_t chars_read = 0;
-
- /// whether we can assume little endianess
- const bool is_little_endian = little_endianess();
-
- /// the SAX parser
- json_sax_t* sax = nullptr;
-};
-} // namespace detail
-} // namespace nlohmann
-
-// #include <nlohmann/detail/input/input_adapters.hpp>
-
// #include <nlohmann/detail/input/lexer.hpp>
@@ -8179,8 +5991,11 @@
public:
using token_type = typename lexer_base<BasicJsonType>::token_type;
- explicit lexer(InputAdapterType&& adapter)
- : ia(std::move(adapter)), decimal_point_char(static_cast<char_int_type>(get_decimal_point())) {}
+ explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false)
+ : ia(std::move(adapter))
+ , ignore_comments(ignore_comments_)
+ , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
+ {}
// delete because of pointer members
lexer(const lexer&) = delete;
@@ -8198,8 +6013,8 @@
JSON_HEDLEY_PURE
static char get_decimal_point() noexcept
{
- const auto loc = localeconv();
- assert(loc != nullptr);
+ const auto* loc = localeconv();
+ JSON_ASSERT(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
}
@@ -8225,7 +6040,7 @@
int get_codepoint()
{
// this function only makes sense after reading `\u`
- assert(current == 'u');
+ JSON_ASSERT(current == 'u');
int codepoint = 0;
const auto factors = { 12u, 8u, 4u, 0u };
@@ -8233,15 +6048,15 @@
{
get();
- if (current >= '0' and current <= '9')
+ if (current >= '0' && current <= '9')
{
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
}
- else if (current >= 'A' and current <= 'F')
+ else if (current >= 'A' && current <= 'F')
{
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
}
- else if (current >= 'a' and current <= 'f')
+ else if (current >= 'a' && current <= 'f')
{
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
}
@@ -8251,7 +6066,7 @@
}
}
- assert(0x0000 <= codepoint and codepoint <= 0xFFFF);
+ JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
return codepoint;
}
@@ -8272,13 +6087,13 @@
*/
bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
{
- assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);
+ JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
add(current);
for (auto range = ranges.begin(); range != ranges.end(); ++range)
{
get();
- if (JSON_HEDLEY_LIKELY(*range <= current and current <= *(++range)))
+ if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))
{
add(current);
}
@@ -8313,7 +6128,7 @@
reset();
// we entered the function by reading an open quote
- assert(current == '\"');
+ JSON_ASSERT(current == '\"');
while (true)
{
@@ -8384,10 +6199,10 @@
}
// check if code point is a high surrogate
- if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
+ if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)
{
// expect next \uxxxx entry
- if (JSON_HEDLEY_LIKELY(get() == '\\' and get() == 'u'))
+ if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u'))
{
const int codepoint2 = get_codepoint();
@@ -8398,7 +6213,7 @@
}
// check if codepoint2 is a low surrogate
- if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
+ if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))
{
// overwrite codepoint
codepoint = static_cast<int>(
@@ -8425,7 +6240,7 @@
}
else
{
- if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
+ if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))
{
error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
return token_type::parse_error;
@@ -8433,7 +6248,7 @@
}
// result of the above calculation yields a proper codepoint
- assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
+ JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
// translate codepoint into bytes
if (codepoint < 0x80)
@@ -8800,7 +6615,7 @@
case 0xDE:
case 0xDF:
{
- if (JSON_HEDLEY_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))
+ if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))
{
return token_type::parse_error;
}
@@ -8810,7 +6625,7 @@
// U+0800..U+0FFF: bytes E0 A0..BF 80..BF
case 0xE0:
{
- if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
+ if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -8834,7 +6649,7 @@
case 0xEE:
case 0xEF:
{
- if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
+ if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -8844,7 +6659,7 @@
// U+D000..U+D7FF: bytes ED 80..9F 80..BF
case 0xED:
{
- if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
+ if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -8854,7 +6669,7 @@
// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
case 0xF0:
{
- if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
+ if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -8866,7 +6681,7 @@
case 0xF2:
case 0xF3:
{
- if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
+ if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -8876,7 +6691,7 @@
// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
case 0xF4:
{
- if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
+ if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
{
return token_type::parse_error;
}
@@ -8893,6 +6708,77 @@
}
}
+ /*!
+ * @brief scan a comment
+ * @return whether comment could be scanned successfully
+ */
+ bool scan_comment()
+ {
+ switch (get())
+ {
+ // single-line comments skip input until a newline or EOF is read
+ case '/':
+ {
+ while (true)
+ {
+ switch (get())
+ {
+ case '\n':
+ case '\r':
+ case std::char_traits<char_type>::eof():
+ case '\0':
+ return true;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // multi-line comments skip input until */ is read
+ case '*':
+ {
+ while (true)
+ {
+ switch (get())
+ {
+ case std::char_traits<char_type>::eof():
+ case '\0':
+ {
+ error_message = "invalid comment; missing closing '*/'";
+ return false;
+ }
+
+ case '*':
+ {
+ switch (get())
+ {
+ case '/':
+ return true;
+
+ default:
+ {
+ unget();
+ continue;
+ }
+ }
+ }
+
+ default:
+ continue;
+ }
+ }
+ }
+
+ // unexpected character after reading '/'
+ default:
+ {
+ error_message = "invalid comment; expecting '/' or '*' after '/'";
+ return false;
+ }
+ }
+ }
+
JSON_HEDLEY_NON_NULL(2)
static void strtof(float& f, const char* str, char** endptr) noexcept
{
@@ -8991,7 +6877,7 @@
// all other characters are rejected outside scan_number()
default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
}
scan_number_minus:
@@ -9238,7 +7124,7 @@
const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
// we checked the number format before
- assert(endptr == token_buffer.data() + token_buffer.size());
+ JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (errno == 0)
{
@@ -9254,7 +7140,7 @@
const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
// we checked the number format before
- assert(endptr == token_buffer.data() + token_buffer.size());
+ JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (errno == 0)
{
@@ -9271,7 +7157,7 @@
strtof(value_float, token_buffer.data(), &endptr);
// we checked the number format before
- assert(endptr == token_buffer.data() + token_buffer.size());
+ JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
return token_type::value_float;
}
@@ -9285,7 +7171,7 @@
token_type scan_literal(const char_type* literal_text, const std::size_t length,
token_type return_type)
{
- assert(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
+ JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
for (std::size_t i = 1; i < length; ++i)
{
if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))
@@ -9377,7 +7263,7 @@
if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
{
- assert(not token_string.empty());
+ JSON_ASSERT(!token_string.empty());
token_string.pop_back();
}
}
@@ -9473,7 +7359,7 @@
if (get() == 0xEF)
{
// check if we completely parse the BOM
- return get() == 0xBB and get() == 0xBF;
+ return get() == 0xBB && get() == 0xBF;
}
// the first character is not the beginning of the BOM; unget it to
@@ -9482,21 +7368,38 @@
return true;
}
+ void skip_whitespace()
+ {
+ do
+ {
+ get();
+ }
+ while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
+ }
+
token_type scan()
{
// initially, skip the BOM
- if (position.chars_read_total == 0 and not skip_bom())
+ if (position.chars_read_total == 0 && !skip_bom())
{
error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
return token_type::parse_error;
}
// read next character and ignore whitespace
- do
+ skip_whitespace();
+
+ // ignore comments
+ while (ignore_comments && current == '/')
{
- get();
+ if (!scan_comment())
+ {
+ return token_type::parse_error;
+ }
+
+ // skip following whitespace
+ skip_whitespace();
}
- while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
switch (current)
{
@@ -9566,6 +7469,9 @@
/// input adapter
InputAdapterType ia;
+ /// whether comments should be ignored (true) or signaled as errors (false)
+ const bool ignore_comments = false;
+
/// the current character
char_int_type current = std::char_traits<char_type>::eof();
@@ -9595,10 +7501,2609 @@
} // namespace detail
} // namespace nlohmann
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/is_sax.hpp>
+
+
+#include <cstdint> // size_t
+#include <utility> // declval
+#include <string> // string
+
+// #include <nlohmann/detail/meta/detected.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+
+namespace nlohmann
+{
+namespace detail
+{
+template<typename T>
+using null_function_t = decltype(std::declval<T&>().null());
+
+template<typename T>
+using boolean_function_t =
+ decltype(std::declval<T&>().boolean(std::declval<bool>()));
+
+template<typename T, typename Integer>
+using number_integer_function_t =
+ decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
+
+template<typename T, typename Unsigned>
+using number_unsigned_function_t =
+ decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
+
+template<typename T, typename Float, typename String>
+using number_float_function_t = decltype(std::declval<T&>().number_float(
+ std::declval<Float>(), std::declval<const String&>()));
+
+template<typename T, typename String>
+using string_function_t =
+ decltype(std::declval<T&>().string(std::declval<String&>()));
+
+template<typename T, typename Binary>
+using binary_function_t =
+ decltype(std::declval<T&>().binary(std::declval<Binary&>()));
+
+template<typename T>
+using start_object_function_t =
+ decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
+
+template<typename T, typename String>
+using key_function_t =
+ decltype(std::declval<T&>().key(std::declval<String&>()));
+
+template<typename T>
+using end_object_function_t = decltype(std::declval<T&>().end_object());
+
+template<typename T>
+using start_array_function_t =
+ decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
+
+template<typename T>
+using end_array_function_t = decltype(std::declval<T&>().end_array());
+
+template<typename T, typename Exception>
+using parse_error_function_t = decltype(std::declval<T&>().parse_error(
+ std::declval<std::size_t>(), std::declval<const std::string&>(),
+ std::declval<const Exception&>()));
+
+template<typename SAX, typename BasicJsonType>
+struct is_sax
+{
+ private:
+ static_assert(is_basic_json<BasicJsonType>::value,
+ "BasicJsonType must be of type basic_json<...>");
+
+ using number_integer_t = typename BasicJsonType::number_integer_t;
+ using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+ using number_float_t = typename BasicJsonType::number_float_t;
+ using string_t = typename BasicJsonType::string_t;
+ using binary_t = typename BasicJsonType::binary_t;
+ using exception_t = typename BasicJsonType::exception;
+
+ public:
+ static constexpr bool value =
+ is_detected_exact<bool, null_function_t, SAX>::value &&
+ is_detected_exact<bool, boolean_function_t, SAX>::value &&
+ is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
+ is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
+ is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
+ is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
+ is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
+ is_detected_exact<bool, start_object_function_t, SAX>::value &&
+ is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
+ is_detected_exact<bool, end_object_function_t, SAX>::value &&
+ is_detected_exact<bool, start_array_function_t, SAX>::value &&
+ is_detected_exact<bool, end_array_function_t, SAX>::value &&
+ is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
+};
+
+template<typename SAX, typename BasicJsonType>
+struct is_sax_static_asserts
+{
+ private:
+ static_assert(is_basic_json<BasicJsonType>::value,
+ "BasicJsonType must be of type basic_json<...>");
+
+ using number_integer_t = typename BasicJsonType::number_integer_t;
+ using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+ using number_float_t = typename BasicJsonType::number_float_t;
+ using string_t = typename BasicJsonType::string_t;
+ using binary_t = typename BasicJsonType::binary_t;
+ using exception_t = typename BasicJsonType::exception;
+
+ public:
+ static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
+ "Missing/invalid function: bool null()");
+ static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
+ "Missing/invalid function: bool boolean(bool)");
+ static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
+ "Missing/invalid function: bool boolean(bool)");
+ static_assert(
+ is_detected_exact<bool, number_integer_function_t, SAX,
+ number_integer_t>::value,
+ "Missing/invalid function: bool number_integer(number_integer_t)");
+ static_assert(
+ is_detected_exact<bool, number_unsigned_function_t, SAX,
+ number_unsigned_t>::value,
+ "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
+ static_assert(is_detected_exact<bool, number_float_function_t, SAX,
+ number_float_t, string_t>::value,
+ "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
+ static_assert(
+ is_detected_exact<bool, string_function_t, SAX, string_t>::value,
+ "Missing/invalid function: bool string(string_t&)");
+ static_assert(
+ is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
+ "Missing/invalid function: bool binary(binary_t&)");
+ static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
+ "Missing/invalid function: bool start_object(std::size_t)");
+ static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
+ "Missing/invalid function: bool key(string_t&)");
+ static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
+ "Missing/invalid function: bool end_object()");
+ static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
+ "Missing/invalid function: bool start_array(std::size_t)");
+ static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
+ "Missing/invalid function: bool end_array()");
+ static_assert(
+ is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
+ "Missing/invalid function: bool parse_error(std::size_t, const "
+ "std::string&, const exception&)");
+};
+} // namespace detail
+} // namespace nlohmann
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+namespace nlohmann
+{
+namespace detail
+{
+
+/// how to treat CBOR tags
+enum class cbor_tag_handler_t
+{
+ error, ///< throw a parse_error exception in case of a tag
+ ignore ///< ignore tags
+};
+
+/*!
+@brief determine system byte order
+
+@return true if and only if system's byte order is little endian
+
+@note from https://stackoverflow.com/a/1001328/266378
+*/
+static inline bool little_endianess(int num = 1) noexcept
+{
+ return *reinterpret_cast<char*>(&num) == 1;
+}
+
+
+///////////////////
+// binary reader //
+///////////////////
+
+/*!
+@brief deserialization of CBOR, MessagePack, and UBJSON values
+*/
+template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
+class binary_reader
+{
+ using number_integer_t = typename BasicJsonType::number_integer_t;
+ using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+ using number_float_t = typename BasicJsonType::number_float_t;
+ using string_t = typename BasicJsonType::string_t;
+ using binary_t = typename BasicJsonType::binary_t;
+ using json_sax_t = SAX;
+ using char_type = typename InputAdapterType::char_type;
+ using char_int_type = typename std::char_traits<char_type>::int_type;
+
+ public:
+ /*!
+ @brief create a binary reader
+
+ @param[in] adapter input adapter to read from
+ */
+ explicit binary_reader(InputAdapterType&& adapter) : ia(std::move(adapter))
+ {
+ (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
+ }
+
+ // make class move-only
+ binary_reader(const binary_reader&) = delete;
+ binary_reader(binary_reader&&) = default;
+ binary_reader& operator=(const binary_reader&) = delete;
+ binary_reader& operator=(binary_reader&&) = default;
+ ~binary_reader() = default;
+
+ /*!
+ @param[in] format the binary format to parse
+ @param[in] sax_ a SAX event processor
+ @param[in] strict whether to expect the input to be consumed completed
+ @param[in] tag_handler how to treat CBOR tags
+
+ @return
+ */
+ JSON_HEDLEY_NON_NULL(3)
+ bool sax_parse(const input_format_t format,
+ json_sax_t* sax_,
+ const bool strict = true,
+ const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+ {
+ sax = sax_;
+ bool result = false;
+
+ switch (format)
+ {
+ case input_format_t::bson:
+ result = parse_bson_internal();
+ break;
+
+ case input_format_t::cbor:
+ result = parse_cbor_internal(true, tag_handler);
+ break;
+
+ case input_format_t::msgpack:
+ result = parse_msgpack_internal();
+ break;
+
+ case input_format_t::ubjson:
+ result = parse_ubjson_internal();
+ break;
+
+ default: // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
+ }
+
+ // strict mode: next byte must be EOF
+ if (result && strict)
+ {
+ if (format == input_format_t::ubjson)
+ {
+ get_ignore_noop();
+ }
+ else
+ {
+ get();
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
+ {
+ return sax->parse_error(chars_read, get_token_string(),
+ parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value")));
+ }
+ }
+
+ return result;
+ }
+
+ private:
+ //////////
+ // BSON //
+ //////////
+
+ /*!
+ @brief Reads in a BSON-object and passes it to the SAX-parser.
+ @return whether a valid BSON-value was passed to the SAX parser
+ */
+ bool parse_bson_internal()
+ {
+ std::int32_t document_size{};
+ get_number<std::int32_t, true>(input_format_t::bson, document_size);
+
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))
+ {
+ return false;
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))
+ {
+ return false;
+ }
+
+ return sax->end_object();
+ }
+
+ /*!
+ @brief Parses a C-style string from the BSON input.
+ @param[in, out] result A reference to the string variable where the read
+ string is to be stored.
+ @return `true` if the \x00-byte indicating the end of the string was
+ encountered before the EOF; false` indicates an unexpected EOF.
+ */
+ bool get_bson_cstr(string_t& result)
+ {
+ auto out = std::back_inserter(result);
+ while (true)
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring")))
+ {
+ return false;
+ }
+ if (current == 0x00)
+ {
+ return true;
+ }
+ *out++ = static_cast<typename string_t::value_type>(current);
+ }
+ }
+
+ /*!
+ @brief Parses a zero-terminated string of length @a len from the BSON
+ input.
+ @param[in] len The length (including the zero-byte at the end) of the
+ string to be read.
+ @param[in, out] result A reference to the string variable where the read
+ string is to be stored.
+ @tparam NumberType The type of the length @a len
+ @pre len >= 1
+ @return `true` if the string was successfully parsed
+ */
+ template<typename NumberType>
+ bool get_bson_string(const NumberType len, string_t& result)
+ {
+ if (JSON_HEDLEY_UNLIKELY(len < 1))
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string")));
+ }
+
+ return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();
+ }
+
+ /*!
+ @brief Parses a byte array input of length @a len from the BSON input.
+ @param[in] len The length of the byte array to be read.
+ @param[in, out] result A reference to the binary variable where the read
+ array is to be stored.
+ @tparam NumberType The type of the length @a len
+ @pre len >= 0
+ @return `true` if the byte array was successfully parsed
+ */
+ template<typename NumberType>
+ bool get_bson_binary(const NumberType len, binary_t& result)
+ {
+ if (JSON_HEDLEY_UNLIKELY(len < 0))
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary")));
+ }
+
+ // All BSON binary values have a subtype
+ std::uint8_t subtype{};
+ get_number<std::uint8_t>(input_format_t::bson, subtype);
+ result.set_subtype(subtype);
+
+ return get_binary(input_format_t::bson, len, result);
+ }
+
+ /*!
+ @brief Read a BSON document element of the given @a element_type.
+ @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
+ @param[in] element_type_parse_position The position in the input stream,
+ where the `element_type` was read.
+ @warning Not all BSON element types are supported yet. An unsupported
+ @a element_type will give rise to a parse_error.114:
+ Unsupported BSON record type 0x...
+ @return whether a valid BSON-object/array was passed to the SAX parser
+ */
+ bool parse_bson_element_internal(const char_int_type element_type,
+ const std::size_t element_type_parse_position)
+ {
+ switch (element_type)
+ {
+ case 0x01: // double
+ {
+ double number{};
+ return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
+ }
+
+ case 0x02: // string
+ {
+ std::int32_t len{};
+ string_t value;
+ return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);
+ }
+
+ case 0x03: // object
+ {
+ return parse_bson_internal();
+ }
+
+ case 0x04: // array
+ {
+ return parse_bson_array();
+ }
+
+ case 0x05: // binary
+ {
+ std::int32_t len{};
+ binary_t value;
+ return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);
+ }
+
+ case 0x08: // boolean
+ {
+ return sax->boolean(get() != 0);
+ }
+
+ case 0x0A: // null
+ {
+ return sax->null();
+ }
+
+ case 0x10: // int32
+ {
+ std::int32_t value{};
+ return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
+ }
+
+ case 0x12: // int64
+ {
+ std::int64_t value{};
+ return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
+ }
+
+ default: // anything else not supported (yet)
+ {
+ std::array<char, 3> cr{{}};
+ (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type));
+ return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data())));
+ }
+ }
+ }
+
+ /*!
+ @brief Read a BSON element list (as specified in the BSON-spec)
+
+ The same binary layout is used for objects and arrays, hence it must be
+ indicated with the argument @a is_array which one is expected
+ (true --> array, false --> object).
+
+ @param[in] is_array Determines if the element list being read is to be
+ treated as an object (@a is_array == false), or as an
+ array (@a is_array == true).
+ @return whether a valid BSON-object/array was passed to the SAX parser
+ */
+ bool parse_bson_element_list(const bool is_array)
+ {
+ string_t key;
+
+ while (auto element_type = get())
+ {
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list")))
+ {
+ return false;
+ }
+
+ const std::size_t element_type_parse_position = chars_read;
+ if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
+ {
+ return false;
+ }
+
+ if (!is_array && !sax->key(key))
+ {
+ return false;
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
+ {
+ return false;
+ }
+
+ // get_bson_cstr only appends
+ key.clear();
+ }
+
+ return true;
+ }
+
+ /*!
+ @brief Reads an array from the BSON input and passes it to the SAX-parser.
+ @return whether a valid BSON-array was passed to the SAX parser
+ */
+ bool parse_bson_array()
+ {
+ std::int32_t document_size{};
+ get_number<std::int32_t, true>(input_format_t::bson, document_size);
+
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))
+ {
+ return false;
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))
+ {
+ return false;
+ }
+
+ return sax->end_array();
+ }
+
+ //////////
+ // CBOR //
+ //////////
+
+ /*!
+ @param[in] get_char whether a new character should be retrieved from the
+ input (true) or whether the last read character should
+ be considered instead (false)
+ @param[in] tag_handler how CBOR tags should be treated
+
+ @return whether a valid CBOR value was passed to the SAX parser
+ */
+ bool parse_cbor_internal(const bool get_char,
+ const cbor_tag_handler_t tag_handler)
+ {
+ switch (get_char ? get() : current)
+ {
+ // EOF
+ case std::char_traits<char_type>::eof():
+ return unexpect_eof(input_format_t::cbor, "value");
+
+ // Integer 0x00..0x17 (0..23)
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x0E:
+ case 0x0F:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ return sax->number_unsigned(static_cast<number_unsigned_t>(current));
+
+ case 0x18: // Unsigned integer (one-byte uint8_t follows)
+ {
+ std::uint8_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+ }
+
+ case 0x19: // Unsigned integer (two-byte uint16_t follows)
+ {
+ std::uint16_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+ }
+
+ case 0x1A: // Unsigned integer (four-byte uint32_t follows)
+ {
+ std::uint32_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+ }
+
+ case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
+ {
+ std::uint64_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+ }
+
+ // Negative integer -1-0x00..-1-0x17 (-1..-24)
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
+
+ case 0x38: // Negative integer (one-byte uint8_t follows)
+ {
+ std::uint8_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+ }
+
+ case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
+ {
+ std::uint16_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+ }
+
+ case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
+ {
+ std::uint32_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+ }
+
+ case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
+ {
+ std::uint64_t number{};
+ return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
+ - static_cast<number_integer_t>(number));
+ }
+
+ // Binary data (0x00..0x17 bytes follow)
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58: // Binary data (one-byte uint8_t for n follows)
+ case 0x59: // Binary data (two-byte uint16_t for n follow)
+ case 0x5A: // Binary data (four-byte uint32_t for n follow)
+ case 0x5B: // Binary data (eight-byte uint64_t for n follow)
+ case 0x5F: // Binary data (indefinite length)
+ {
+ binary_t b;
+ return get_cbor_binary(b) && sax->binary(b);
+ }
+
+ // UTF-8 string (0x00..0x17 bytes follow)
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+ case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+ case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
+ case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
+ case 0x7F: // UTF-8 string (indefinite length)
+ {
+ string_t s;
+ return get_cbor_string(s) && sax->string(s);
+ }
+
+ // array (0x00..0x17 data items follow)
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8A:
+ case 0x8B:
+ case 0x8C:
+ case 0x8D:
+ case 0x8E:
+ case 0x8F:
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
+
+ case 0x98: // array (one-byte uint8_t for n follows)
+ {
+ std::uint8_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0x99: // array (two-byte uint16_t for n follow)
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0x9A: // array (four-byte uint32_t for n follow)
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0x9B: // array (eight-byte uint64_t for n follow)
+ {
+ std::uint64_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0x9F: // array (indefinite length)
+ return get_cbor_array(std::size_t(-1), tag_handler);
+
+ // map (0x00..0x17 pairs of data items follow)
+ case 0xA0:
+ case 0xA1:
+ case 0xA2:
+ case 0xA3:
+ case 0xA4:
+ case 0xA5:
+ case 0xA6:
+ case 0xA7:
+ case 0xA8:
+ case 0xA9:
+ case 0xAA:
+ case 0xAB:
+ case 0xAC:
+ case 0xAD:
+ case 0xAE:
+ case 0xAF:
+ case 0xB0:
+ case 0xB1:
+ case 0xB2:
+ case 0xB3:
+ case 0xB4:
+ case 0xB5:
+ case 0xB6:
+ case 0xB7:
+ return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
+
+ case 0xB8: // map (one-byte uint8_t for n follows)
+ {
+ std::uint8_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0xB9: // map (two-byte uint16_t for n follow)
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0xBA: // map (four-byte uint32_t for n follow)
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0xBB: // map (eight-byte uint64_t for n follow)
+ {
+ std::uint64_t len{};
+ return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+ }
+
+ case 0xBF: // map (indefinite length)
+ return get_cbor_object(std::size_t(-1), tag_handler);
+
+ case 0xC6: // tagged item
+ case 0xC7:
+ case 0xC8:
+ case 0xC9:
+ case 0xCA:
+ case 0xCB:
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ case 0xCF:
+ case 0xD0:
+ case 0xD1:
+ case 0xD2:
+ case 0xD3:
+ case 0xD4:
+ case 0xD8: // tagged item (1 bytes follow)
+ case 0xD9: // tagged item (2 bytes follow)
+ case 0xDA: // tagged item (4 bytes follow)
+ case 0xDB: // tagged item (8 bytes follow)
+ {
+ switch (tag_handler)
+ {
+ case cbor_tag_handler_t::error:
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value")));
+ }
+
+ case cbor_tag_handler_t::ignore:
+ {
+ switch (current)
+ {
+ case 0xD8:
+ {
+ std::uint8_t len{};
+ get_number(input_format_t::cbor, len);
+ break;
+ }
+ case 0xD9:
+ {
+ std::uint16_t len{};
+ get_number(input_format_t::cbor, len);
+ break;
+ }
+ case 0xDA:
+ {
+ std::uint32_t len{};
+ get_number(input_format_t::cbor, len);
+ break;
+ }
+ case 0xDB:
+ {
+ std::uint64_t len{};
+ get_number(input_format_t::cbor, len);
+ break;
+ }
+ default:
+ break;
+ }
+ return parse_cbor_internal(true, tag_handler);
+ }
+
+ default: // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
+ }
+ }
+
+ case 0xF4: // false
+ return sax->boolean(false);
+
+ case 0xF5: // true
+ return sax->boolean(true);
+
+ case 0xF6: // null
+ return sax->null();
+
+ case 0xF9: // Half-Precision Float (two-byte IEEE 754)
+ {
+ const auto byte1_raw = get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
+ {
+ return false;
+ }
+ const auto byte2_raw = get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
+ {
+ return false;
+ }
+
+ const auto byte1 = static_cast<unsigned char>(byte1_raw);
+ const auto byte2 = static_cast<unsigned char>(byte2_raw);
+
+ // code from RFC 7049, Appendix D, Figure 3:
+ // As half-precision floating-point numbers were only added
+ // to IEEE 754 in 2008, today's programming platforms often
+ // still only have limited support for them. It is very
+ // easy to include at least decoding support for them even
+ // without such support. An example of a small decoder for
+ // half-precision floating-point numbers in the C language
+ // is shown in Fig. 3.
+ const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
+ const double val = [&half]
+ {
+ const int exp = (half >> 10u) & 0x1Fu;
+ const unsigned int mant = half & 0x3FFu;
+ JSON_ASSERT(0 <= exp&& exp <= 32);
+ JSON_ASSERT(mant <= 1024);
+ switch (exp)
+ {
+ case 0:
+ return std::ldexp(mant, -24);
+ case 31:
+ return (mant == 0)
+ ? std::numeric_limits<double>::infinity()
+ : std::numeric_limits<double>::quiet_NaN();
+ default:
+ return std::ldexp(mant + 1024, exp - 25);
+ }
+ }();
+ return sax->number_float((half & 0x8000u) != 0
+ ? static_cast<number_float_t>(-val)
+ : static_cast<number_float_t>(val), "");
+ }
+
+ case 0xFA: // Single-Precision Float (four-byte IEEE 754)
+ {
+ float number{};
+ return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
+ }
+
+ case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
+ {
+ double number{};
+ return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
+ }
+
+ default: // anything else (0xFF is handled inside the other types)
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value")));
+ }
+ }
+ }
+
+ /*!
+ @brief reads a CBOR string
+
+ This function first reads starting bytes to determine the expected
+ string length and then copies this number of bytes into a string.
+ Additionally, CBOR's strings with indefinite lengths are supported.
+
+ @param[out] result created string
+
+ @return whether string creation completed
+ */
+ bool get_cbor_string(string_t& result)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
+ {
+ return false;
+ }
+
+ switch (current)
+ {
+ // UTF-8 string (0x00..0x17 bytes follow)
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ {
+ return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
+ }
+
+ case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+ {
+ std::uint8_t len{};
+ return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+ }
+
+ case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+ }
+
+ case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+ }
+
+ case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
+ {
+ std::uint64_t len{};
+ return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+ }
+
+ case 0x7F: // UTF-8 string (indefinite length)
+ {
+ while (get() != 0xFF)
+ {
+ string_t chunk;
+ if (!get_cbor_string(chunk))
+ {
+ return false;
+ }
+ result.append(chunk);
+ }
+ return true;
+ }
+
+ default:
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string")));
+ }
+ }
+ }
+
+ /*!
+ @brief reads a CBOR byte array
+
+ This function first reads starting bytes to determine the expected
+ byte array length and then copies this number of bytes into the byte array.
+ Additionally, CBOR's byte arrays with indefinite lengths are supported.
+
+ @param[out] result created byte array
+
+ @return whether byte array creation completed
+ */
+ bool get_cbor_binary(binary_t& result)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
+ {
+ return false;
+ }
+
+ switch (current)
+ {
+ // Binary data (0x00..0x17 bytes follow)
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ {
+ return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
+ }
+
+ case 0x58: // Binary data (one-byte uint8_t for n follows)
+ {
+ std::uint8_t len{};
+ return get_number(input_format_t::cbor, len) &&
+ get_binary(input_format_t::cbor, len, result);
+ }
+
+ case 0x59: // Binary data (two-byte uint16_t for n follow)
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::cbor, len) &&
+ get_binary(input_format_t::cbor, len, result);
+ }
+
+ case 0x5A: // Binary data (four-byte uint32_t for n follow)
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::cbor, len) &&
+ get_binary(input_format_t::cbor, len, result);
+ }
+
+ case 0x5B: // Binary data (eight-byte uint64_t for n follow)
+ {
+ std::uint64_t len{};
+ return get_number(input_format_t::cbor, len) &&
+ get_binary(input_format_t::cbor, len, result);
+ }
+
+ case 0x5F: // Binary data (indefinite length)
+ {
+ while (get() != 0xFF)
+ {
+ binary_t chunk;
+ if (!get_cbor_binary(chunk))
+ {
+ return false;
+ }
+ result.insert(result.end(), chunk.begin(), chunk.end());
+ }
+ return true;
+ }
+
+ default:
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary")));
+ }
+ }
+ }
+
+ /*!
+ @param[in] len the length of the array or std::size_t(-1) for an
+ array of indefinite size
+ @param[in] tag_handler how CBOR tags should be treated
+ @return whether array creation completed
+ */
+ bool get_cbor_array(const std::size_t len,
+ const cbor_tag_handler_t tag_handler)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
+ {
+ return false;
+ }
+
+ if (len != std::size_t(-1))
+ {
+ for (std::size_t i = 0; i < len; ++i)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ while (get() != 0xFF)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
+ {
+ return false;
+ }
+ }
+ }
+
+ return sax->end_array();
+ }
+
+ /*!
+ @param[in] len the length of the object or std::size_t(-1) for an
+ object of indefinite size
+ @param[in] tag_handler how CBOR tags should be treated
+ @return whether object creation completed
+ */
+ bool get_cbor_object(const std::size_t len,
+ const cbor_tag_handler_t tag_handler)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
+ {
+ return false;
+ }
+
+ string_t key;
+ if (len != std::size_t(-1))
+ {
+ for (std::size_t i = 0; i < len; ++i)
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
+ {
+ return false;
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+ {
+ return false;
+ }
+ key.clear();
+ }
+ }
+ else
+ {
+ while (get() != 0xFF)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
+ {
+ return false;
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+ {
+ return false;
+ }
+ key.clear();
+ }
+ }
+
+ return sax->end_object();
+ }
+
+ /////////////
+ // MsgPack //
+ /////////////
+
+ /*!
+ @return whether a valid MessagePack value was passed to the SAX parser
+ */
+ bool parse_msgpack_internal()
+ {
+ switch (get())
+ {
+ // EOF
+ case std::char_traits<char_type>::eof():
+ return unexpect_eof(input_format_t::msgpack, "value");
+
+ // positive fixint
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x0E:
+ case 0x0F:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1A:
+ case 0x1B:
+ case 0x1C:
+ case 0x1D:
+ case 0x1E:
+ case 0x1F:
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4A:
+ case 0x4B:
+ case 0x4C:
+ case 0x4D:
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ return sax->number_unsigned(static_cast<number_unsigned_t>(current));
+
+ // fixmap
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8A:
+ case 0x8B:
+ case 0x8C:
+ case 0x8D:
+ case 0x8E:
+ case 0x8F:
+ return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
+
+ // fixarray
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9A:
+ case 0x9B:
+ case 0x9C:
+ case 0x9D:
+ case 0x9E:
+ case 0x9F:
+ return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
+
+ // fixstr
+ case 0xA0:
+ case 0xA1:
+ case 0xA2:
+ case 0xA3:
+ case 0xA4:
+ case 0xA5:
+ case 0xA6:
+ case 0xA7:
+ case 0xA8:
+ case 0xA9:
+ case 0xAA:
+ case 0xAB:
+ case 0xAC:
+ case 0xAD:
+ case 0xAE:
+ case 0xAF:
+ case 0xB0:
+ case 0xB1:
+ case 0xB2:
+ case 0xB3:
+ case 0xB4:
+ case 0xB5:
+ case 0xB6:
+ case 0xB7:
+ case 0xB8:
+ case 0xB9:
+ case 0xBA:
+ case 0xBB:
+ case 0xBC:
+ case 0xBD:
+ case 0xBE:
+ case 0xBF:
+ case 0xD9: // str 8
+ case 0xDA: // str 16
+ case 0xDB: // str 32
+ {
+ string_t s;
+ return get_msgpack_string(s) && sax->string(s);
+ }
+
+ case 0xC0: // nil
+ return sax->null();
+
+ case 0xC2: // false
+ return sax->boolean(false);
+
+ case 0xC3: // true
+ return sax->boolean(true);
+
+ case 0xC4: // bin 8
+ case 0xC5: // bin 16
+ case 0xC6: // bin 32
+ case 0xC7: // ext 8
+ case 0xC8: // ext 16
+ case 0xC9: // ext 32
+ case 0xD4: // fixext 1
+ case 0xD5: // fixext 2
+ case 0xD6: // fixext 4
+ case 0xD7: // fixext 8
+ case 0xD8: // fixext 16
+ {
+ binary_t b;
+ return get_msgpack_binary(b) && sax->binary(b);
+ }
+
+ case 0xCA: // float 32
+ {
+ float number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
+ }
+
+ case 0xCB: // float 64
+ {
+ double number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
+ }
+
+ case 0xCC: // uint 8
+ {
+ std::uint8_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+ }
+
+ case 0xCD: // uint 16
+ {
+ std::uint16_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+ }
+
+ case 0xCE: // uint 32
+ {
+ std::uint32_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+ }
+
+ case 0xCF: // uint 64
+ {
+ std::uint64_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+ }
+
+ case 0xD0: // int 8
+ {
+ std::int8_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ }
+
+ case 0xD1: // int 16
+ {
+ std::int16_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ }
+
+ case 0xD2: // int 32
+ {
+ std::int32_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ }
+
+ case 0xD3: // int 64
+ {
+ std::int64_t number{};
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ }
+
+ case 0xDC: // array 16
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
+ }
+
+ case 0xDD: // array 32
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
+ }
+
+ case 0xDE: // map 16
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
+ }
+
+ case 0xDF: // map 32
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
+ }
+
+ // negative fixint
+ case 0xE0:
+ case 0xE1:
+ case 0xE2:
+ case 0xE3:
+ case 0xE4:
+ case 0xE5:
+ case 0xE6:
+ case 0xE7:
+ case 0xE8:
+ case 0xE9:
+ case 0xEA:
+ case 0xEB:
+ case 0xEC:
+ case 0xED:
+ case 0xEE:
+ case 0xEF:
+ case 0xF0:
+ case 0xF1:
+ case 0xF2:
+ case 0xF3:
+ case 0xF4:
+ case 0xF5:
+ case 0xF6:
+ case 0xF7:
+ case 0xF8:
+ case 0xF9:
+ case 0xFA:
+ case 0xFB:
+ case 0xFC:
+ case 0xFD:
+ case 0xFE:
+ case 0xFF:
+ return sax->number_integer(static_cast<std::int8_t>(current));
+
+ default: // anything else
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value")));
+ }
+ }
+ }
+
+ /*!
+ @brief reads a MessagePack string
+
+ This function first reads starting bytes to determine the expected
+ string length and then copies this number of bytes into a string.
+
+ @param[out] result created string
+
+ @return whether string creation completed
+ */
+ bool get_msgpack_string(string_t& result)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string")))
+ {
+ return false;
+ }
+
+ switch (current)
+ {
+ // fixstr
+ case 0xA0:
+ case 0xA1:
+ case 0xA2:
+ case 0xA3:
+ case 0xA4:
+ case 0xA5:
+ case 0xA6:
+ case 0xA7:
+ case 0xA8:
+ case 0xA9:
+ case 0xAA:
+ case 0xAB:
+ case 0xAC:
+ case 0xAD:
+ case 0xAE:
+ case 0xAF:
+ case 0xB0:
+ case 0xB1:
+ case 0xB2:
+ case 0xB3:
+ case 0xB4:
+ case 0xB5:
+ case 0xB6:
+ case 0xB7:
+ case 0xB8:
+ case 0xB9:
+ case 0xBA:
+ case 0xBB:
+ case 0xBC:
+ case 0xBD:
+ case 0xBE:
+ case 0xBF:
+ {
+ return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
+ }
+
+ case 0xD9: // str 8
+ {
+ std::uint8_t len{};
+ return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+ }
+
+ case 0xDA: // str 16
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+ }
+
+ case 0xDB: // str 32
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+ }
+
+ default:
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string")));
+ }
+ }
+ }
+
+ /*!
+ @brief reads a MessagePack byte array
+
+ This function first reads starting bytes to determine the expected
+ byte array length and then copies this number of bytes into a byte array.
+
+ @param[out] result created byte array
+
+ @return whether byte array creation completed
+ */
+ bool get_msgpack_binary(binary_t& result)
+ {
+ // helper function to set the subtype
+ auto assign_and_return_true = [&result](std::int8_t subtype)
+ {
+ result.set_subtype(static_cast<std::uint8_t>(subtype));
+ return true;
+ };
+
+ switch (current)
+ {
+ case 0xC4: // bin 8
+ {
+ std::uint8_t len{};
+ return get_number(input_format_t::msgpack, len) &&
+ get_binary(input_format_t::msgpack, len, result);
+ }
+
+ case 0xC5: // bin 16
+ {
+ std::uint16_t len{};
+ return get_number(input_format_t::msgpack, len) &&
+ get_binary(input_format_t::msgpack, len, result);
+ }
+
+ case 0xC6: // bin 32
+ {
+ std::uint32_t len{};
+ return get_number(input_format_t::msgpack, len) &&
+ get_binary(input_format_t::msgpack, len, result);
+ }
+
+ case 0xC7: // ext 8
+ {
+ std::uint8_t len{};
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, len) &&
+ get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, len, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ case 0xC8: // ext 16
+ {
+ std::uint16_t len{};
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, len) &&
+ get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, len, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ case 0xC9: // ext 32
+ {
+ std::uint32_t len{};
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, len) &&
+ get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, len, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ case 0xD4: // fixext 1
+ {
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, 1, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ case 0xD5: // fixext 2
+ {
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, 2, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ case 0xD6: // fixext 4
+ {
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, 4, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ case 0xD7: // fixext 8
+ {
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, 8, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ case 0xD8: // fixext 16
+ {
+ std::int8_t subtype{};
+ return get_number(input_format_t::msgpack, subtype) &&
+ get_binary(input_format_t::msgpack, 16, result) &&
+ assign_and_return_true(subtype);
+ }
+
+ default: // LCOV_EXCL_LINE
+ return false; // LCOV_EXCL_LINE
+ }
+ }
+
+ /*!
+ @param[in] len the length of the array
+ @return whether array creation completed
+ */
+ bool get_msgpack_array(const std::size_t len)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
+ {
+ return false;
+ }
+
+ for (std::size_t i = 0; i < len; ++i)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
+ {
+ return false;
+ }
+ }
+
+ return sax->end_array();
+ }
+
+ /*!
+ @param[in] len the length of the object
+ @return whether object creation completed
+ */
+ bool get_msgpack_object(const std::size_t len)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
+ {
+ return false;
+ }
+
+ string_t key;
+ for (std::size_t i = 0; i < len; ++i)
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
+ {
+ return false;
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
+ {
+ return false;
+ }
+ key.clear();
+ }
+
+ return sax->end_object();
+ }
+
+ ////////////
+ // UBJSON //
+ ////////////
+
+ /*!
+ @param[in] get_char whether a new character should be retrieved from the
+ input (true, default) or whether the last read
+ character should be considered instead
+
+ @return whether a valid UBJSON value was passed to the SAX parser
+ */
+ bool parse_ubjson_internal(const bool get_char = true)
+ {
+ return get_ubjson_value(get_char ? get_ignore_noop() : current);
+ }
+
+ /*!
+ @brief reads a UBJSON string
+
+ This function is either called after reading the 'S' byte explicitly
+ indicating a string, or in case of an object key where the 'S' byte can be
+ left out.
+
+ @param[out] result created string
+ @param[in] get_char whether a new character should be retrieved from the
+ input (true, default) or whether the last read
+ character should be considered instead
+
+ @return whether string creation completed
+ */
+ bool get_ubjson_string(string_t& result, const bool get_char = true)
+ {
+ if (get_char)
+ {
+ get(); // TODO(niels): may we ignore N here?
+ }
+
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value")))
+ {
+ return false;
+ }
+
+ switch (current)
+ {
+ case 'U':
+ {
+ std::uint8_t len{};
+ return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);
+ }
+
+ case 'i':
+ {
+ std::int8_t len{};
+ return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);
+ }
+
+ case 'I':
+ {
+ std::int16_t len{};
+ return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);
+ }
+
+ case 'l':
+ {
+ std::int32_t len{};
+ return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);
+ }
+
+ case 'L':
+ {
+ std::int64_t len{};
+ return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);
+ }
+
+ default:
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string")));
+ }
+ }
+
+ /*!
+ @param[out] result determined size
+ @return whether size determination completed
+ */
+ bool get_ubjson_size_value(std::size_t& result)
+ {
+ switch (get_ignore_noop())
+ {
+ case 'U':
+ {
+ std::uint8_t number{};
+ if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))
+ {
+ return false;
+ }
+ result = static_cast<std::size_t>(number);
+ return true;
+ }
+
+ case 'i':
+ {
+ std::int8_t number{};
+ if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))
+ {
+ return false;
+ }
+ result = static_cast<std::size_t>(number);
+ return true;
+ }
+
+ case 'I':
+ {
+ std::int16_t number{};
+ if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))
+ {
+ return false;
+ }
+ result = static_cast<std::size_t>(number);
+ return true;
+ }
+
+ case 'l':
+ {
+ std::int32_t number{};
+ if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))
+ {
+ return false;
+ }
+ result = static_cast<std::size_t>(number);
+ return true;
+ }
+
+ case 'L':
+ {
+ std::int64_t number{};
+ if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))
+ {
+ return false;
+ }
+ result = static_cast<std::size_t>(number);
+ return true;
+ }
+
+ default:
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size")));
+ }
+ }
+ }
+
+ /*!
+ @brief determine the type and size for a container
+
+ In the optimized UBJSON format, a type and a size can be provided to allow
+ for a more compact representation.
+
+ @param[out] result pair of the size and the type
+
+ @return whether pair creation completed
+ */
+ bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result)
+ {
+ result.first = string_t::npos; // size
+ result.second = 0; // type
+
+ get_ignore_noop();
+
+ if (current == '$')
+ {
+ result.second = get(); // must not ignore 'N', because 'N' maybe the type
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "type")))
+ {
+ return false;
+ }
+
+ get_ignore_noop();
+ if (JSON_HEDLEY_UNLIKELY(current != '#'))
+ {
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value")))
+ {
+ return false;
+ }
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size")));
+ }
+
+ return get_ubjson_size_value(result.first);
+ }
+
+ if (current == '#')
+ {
+ return get_ubjson_size_value(result.first);
+ }
+
+ return true;
+ }
+
+ /*!
+ @param prefix the previously read or set type prefix
+ @return whether value creation completed
+ */
+ bool get_ubjson_value(const char_int_type prefix)
+ {
+ switch (prefix)
+ {
+ case std::char_traits<char_type>::eof(): // EOF
+ return unexpect_eof(input_format_t::ubjson, "value");
+
+ case 'T': // true
+ return sax->boolean(true);
+ case 'F': // false
+ return sax->boolean(false);
+
+ case 'Z': // null
+ return sax->null();
+
+ case 'U':
+ {
+ std::uint8_t number{};
+ return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number);
+ }
+
+ case 'i':
+ {
+ std::int8_t number{};
+ return get_number(input_format_t::ubjson, number) && sax->number_integer(number);
+ }
+
+ case 'I':
+ {
+ std::int16_t number{};
+ return get_number(input_format_t::ubjson, number) && sax->number_integer(number);
+ }
+
+ case 'l':
+ {
+ std::int32_t number{};
+ return get_number(input_format_t::ubjson, number) && sax->number_integer(number);
+ }
+
+ case 'L':
+ {
+ std::int64_t number{};
+ return get_number(input_format_t::ubjson, number) && sax->number_integer(number);
+ }
+
+ case 'd':
+ {
+ float number{};
+ return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast<number_float_t>(number), "");
+ }
+
+ case 'D':
+ {
+ double number{};
+ return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast<number_float_t>(number), "");
+ }
+
+ case 'H':
+ {
+ return get_ubjson_high_precision_number();
+ }
+
+ case 'C': // char
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "char")))
+ {
+ return false;
+ }
+ if (JSON_HEDLEY_UNLIKELY(current > 127))
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char")));
+ }
+ string_t s(1, static_cast<typename string_t::value_type>(current));
+ return sax->string(s);
+ }
+
+ case 'S': // string
+ {
+ string_t s;
+ return get_ubjson_string(s) && sax->string(s);
+ }
+
+ case '[': // array
+ return get_ubjson_array();
+
+ case '{': // object
+ return get_ubjson_object();
+
+ default: // anything else
+ {
+ auto last_token = get_token_string();
+ return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value")));
+ }
+ }
+ }
+
+ /*!
+ @return whether array creation completed
+ */
+ bool get_ubjson_array()
+ {
+ std::pair<std::size_t, char_int_type> size_and_type;
+ if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
+ {
+ return false;
+ }
+
+ if (size_and_type.first != string_t::npos)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
+ {
+ return false;
+ }
+
+ if (size_and_type.second != 0)
+ {
+ if (size_and_type.second != 'N')
+ {
+ for (std::size_t i = 0; i < size_and_type.first; ++i)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (std::size_t i = 0; i < size_and_type.first; ++i)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))
+ {
+ return false;
+ }
+
+ while (current != ']')
+ {
+ if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))
+ {
+ return false;
+ }
+ get_ignore_noop();
+ }
+ }
+
+ return sax->end_array();
+ }
+
+ /*!
+ @return whether object creation completed
+ */
+ bool get_ubjson_object()
+ {
+ std::pair<std::size_t, char_int_type> size_and_type;
+ if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
+ {
+ return false;
+ }
+
+ string_t key;
+ if (size_and_type.first != string_t::npos)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
+ {
+ return false;
+ }
+
+ if (size_and_type.second != 0)
+ {
+ for (std::size_t i = 0; i < size_and_type.first; ++i)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
+ {
+ return false;
+ }
+ if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+ {
+ return false;
+ }
+ key.clear();
+ }
+ }
+ else
+ {
+ for (std::size_t i = 0; i < size_and_type.first; ++i)
+ {
+ if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
+ {
+ return false;
+ }
+ if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+ {
+ return false;
+ }
+ key.clear();
+ }
+ }
+ }
+ else
+ {
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))
+ {
+ return false;
+ }
+
+ while (current != '}')
+ {
+ if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))
+ {
+ return false;
+ }
+ if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+ {
+ return false;
+ }
+ get_ignore_noop();
+ key.clear();
+ }
+ }
+
+ return sax->end_object();
+ }
+
+ // Note, no reader for UBJSON binary types is implemented because they do
+ // not exist
+
+ bool get_ubjson_high_precision_number()
+ {
+ // get size of following number string
+ std::size_t size{};
+ auto res = get_ubjson_size_value(size);
+ if (JSON_HEDLEY_UNLIKELY(!res))
+ {
+ return res;
+ }
+
+ // get number string
+ std::vector<char> number_vector;
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "number")))
+ {
+ return false;
+ }
+ number_vector.push_back(static_cast<char>(current));
+ }
+
+ // parse number string
+ auto number_ia = detail::input_adapter(std::forward<decltype(number_vector)>(number_vector));
+ auto number_lexer = detail::lexer<BasicJsonType, decltype(number_ia)>(std::move(number_ia), false);
+ const auto result_number = number_lexer.scan();
+ const auto number_string = number_lexer.get_token_string();
+ const auto result_remainder = number_lexer.scan();
+
+ using token_type = typename detail::lexer_base<BasicJsonType>::token_type;
+
+ if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
+ {
+ return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number")));
+ }
+
+ switch (result_number)
+ {
+ case token_type::value_integer:
+ return sax->number_integer(number_lexer.get_number_integer());
+ case token_type::value_unsigned:
+ return sax->number_unsigned(number_lexer.get_number_unsigned());
+ case token_type::value_float:
+ return sax->number_float(number_lexer.get_number_float(), std::move(number_string));
+ default:
+ return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number")));
+ }
+ }
+
+ ///////////////////////
+ // Utility functions //
+ ///////////////////////
+
+ /*!
+ @brief get next character from the input
+
+ This function provides the interface to the used input adapter. It does
+ not throw in case the input reached EOF, but returns a -'ve valued
+ `std::char_traits<char_type>::eof()` in that case.
+
+ @return character read from the input
+ */
+ char_int_type get()
+ {
+ ++chars_read;
+ return current = ia.get_character();
+ }
+
+ /*!
+ @return character read from the input after ignoring all 'N' entries
+ */
+ char_int_type get_ignore_noop()
+ {
+ do
+ {
+ get();
+ }
+ while (current == 'N');
+
+ return current;
+ }
+
+ /*
+ @brief read a number from the input
+
+ @tparam NumberType the type of the number
+ @param[in] format the current format (for diagnostics)
+ @param[out] result number of type @a NumberType
+
+ @return whether conversion completed
+
+ @note This function needs to respect the system's endianess, because
+ bytes in CBOR, MessagePack, and UBJSON are stored in network order
+ (big endian) and therefore need reordering on little endian systems.
+ */
+ template<typename NumberType, bool InputIsLittleEndian = false>
+ bool get_number(const input_format_t format, NumberType& result)
+ {
+ // step 1: read input into array with system's byte order
+ std::array<std::uint8_t, sizeof(NumberType)> vec;
+ for (std::size_t i = 0; i < sizeof(NumberType); ++i)
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
+ {
+ return false;
+ }
+
+ // reverse byte order prior to conversion if necessary
+ if (is_little_endian != InputIsLittleEndian)
+ {
+ vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
+ }
+ else
+ {
+ vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
+ }
+ }
+
+ // step 2: convert array into number of type T and return
+ std::memcpy(&result, vec.data(), sizeof(NumberType));
+ return true;
+ }
+
+ /*!
+ @brief create a string by reading characters from the input
+
+ @tparam NumberType the type of the number
+ @param[in] format the current format (for diagnostics)
+ @param[in] len number of characters to read
+ @param[out] result string created by reading @a len bytes
+
+ @return whether string creation completed
+
+ @note We can not reserve @a len bytes for the result, because @a len
+ may be too large. Usually, @ref unexpect_eof() detects the end of
+ the input before we run out of string memory.
+ */
+ template<typename NumberType>
+ bool get_string(const input_format_t format,
+ const NumberType len,
+ string_t& result)
+ {
+ bool success = true;
+ for (NumberType i = 0; i < len; i++)
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string")))
+ {
+ success = false;
+ break;
+ }
+ result.push_back(static_cast<typename string_t::value_type>(current));
+ };
+ return success;
+ }
+
+ /*!
+ @brief create a byte array by reading bytes from the input
+
+ @tparam NumberType the type of the number
+ @param[in] format the current format (for diagnostics)
+ @param[in] len number of bytes to read
+ @param[out] result byte array created by reading @a len bytes
+
+ @return whether byte array creation completed
+
+ @note We can not reserve @a len bytes for the result, because @a len
+ may be too large. Usually, @ref unexpect_eof() detects the end of
+ the input before we run out of memory.
+ */
+ template<typename NumberType>
+ bool get_binary(const input_format_t format,
+ const NumberType len,
+ binary_t& result)
+ {
+ bool success = true;
+ for (NumberType i = 0; i < len; i++)
+ {
+ get();
+ if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary")))
+ {
+ success = false;
+ break;
+ }
+ result.push_back(static_cast<std::uint8_t>(current));
+ }
+ return success;
+ }
+
+ /*!
+ @param[in] format the current format (for diagnostics)
+ @param[in] context further context information (for diagnostics)
+ @return whether the last read character is not EOF
+ */
+ JSON_HEDLEY_NON_NULL(3)
+ bool unexpect_eof(const input_format_t format, const char* context) const
+ {
+ if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
+ {
+ return sax->parse_error(chars_read, "<end of file>",
+ parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context)));
+ }
+ return true;
+ }
+
+ /*!
+ @return a string representation of the last read byte
+ */
+ std::string get_token_string() const
+ {
+ std::array<char, 3> cr{{}};
+ (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current));
+ return std::string{cr.data()};
+ }
+
+ /*!
+ @param[in] format the current format
+ @param[in] detail a detailed error message
+ @param[in] context further context information
+ @return a message string to use in the parse_error exceptions
+ */
+ std::string exception_message(const input_format_t format,
+ const std::string& detail,
+ const std::string& context) const
+ {
+ std::string error_msg = "syntax error while parsing ";
+
+ switch (format)
+ {
+ case input_format_t::cbor:
+ error_msg += "CBOR";
+ break;
+
+ case input_format_t::msgpack:
+ error_msg += "MessagePack";
+ break;
+
+ case input_format_t::ubjson:
+ error_msg += "UBJSON";
+ break;
+
+ case input_format_t::bson:
+ error_msg += "BSON";
+ break;
+
+ default: // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
+ }
+
+ return error_msg + " " + context + ": " + detail;
+ }
+
+ private:
+ /// input adapter
+ InputAdapterType ia;
+
+ /// the current character
+ char_int_type current = std::char_traits<char_type>::eof();
+
+ /// the number of characters read
+ std::size_t chars_read = 0;
+
+ /// whether we can assume little endianess
+ const bool is_little_endian = little_endianess();
+
+ /// the SAX parser
+ json_sax_t* sax = nullptr;
+};
+} // namespace detail
+} // namespace nlohmann
+
+// #include <nlohmann/detail/input/input_adapters.hpp>
+
+// #include <nlohmann/detail/input/lexer.hpp>
+
// #include <nlohmann/detail/input/parser.hpp>
-#include <cassert> // assert
#include <cmath> // isfinite
#include <cstdint> // uint8_t
#include <functional> // function
@@ -9668,8 +10173,11 @@
/// a parser reading from an input adapter
explicit parser(InputAdapterType&& adapter,
const parser_callback_t<BasicJsonType> cb = nullptr,
- const bool allow_exceptions_ = true)
- : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)
+ const bool allow_exceptions_ = true,
+ const bool skip_comments = false)
+ : callback(cb)
+ , m_lexer(std::move(adapter), skip_comments)
+ , allow_exceptions(allow_exceptions_)
{
// read first token
get_token();
@@ -9694,7 +10202,7 @@
result.assert_invariant();
// in strict mode, input must be completely read
- if (strict and (get_token() != token_type::end_of_input))
+ if (strict && (get_token() != token_type::end_of_input))
{
sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
@@ -9723,7 +10231,7 @@
result.assert_invariant();
// in strict mode, input must be completely read
- if (strict and (get_token() != token_type::end_of_input))
+ if (strict && (get_token() != token_type::end_of_input))
{
sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
@@ -9752,7 +10260,7 @@
return sax_parse(&sax_acceptor, strict);
}
- template <typename SAX>
+ template<typename SAX>
JSON_HEDLEY_NON_NULL(2)
bool sax_parse(SAX* sax, const bool strict = true)
{
@@ -9760,7 +10268,7 @@
const bool result = sax_parse_internal(sax);
// strict mode: next byte must be EOF
- if (result and strict and (get_token() != token_type::end_of_input))
+ if (result && strict && (get_token() != token_type::end_of_input))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
@@ -9772,7 +10280,7 @@
}
private:
- template <typename SAX>
+ template<typename SAX>
JSON_HEDLEY_NON_NULL(2)
bool sax_parse_internal(SAX* sax)
{
@@ -9784,14 +10292,14 @@
while (true)
{
- if (not skip_to_state_evaluation)
+ if (!skip_to_state_evaluation)
{
// invariant: get_token() was called before each iteration
switch (last_token)
{
case token_type::begin_object:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))
{
return false;
}
@@ -9799,7 +10307,7 @@
// closing } -> we are done
if (get_token() == token_type::end_object)
{
- if (JSON_HEDLEY_UNLIKELY(not sax->end_object()))
+ if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
{
return false;
}
@@ -9814,7 +10322,7 @@
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::value_string, "object key")));
}
- if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string())))
+ if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
{
return false;
}
@@ -9838,7 +10346,7 @@
case token_type::begin_array:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
+ if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))
{
return false;
}
@@ -9846,7 +10354,7 @@
// closing ] -> we are done
if (get_token() == token_type::end_array)
{
- if (JSON_HEDLEY_UNLIKELY(not sax->end_array()))
+ if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
{
return false;
}
@@ -9864,14 +10372,14 @@
{
const auto res = m_lexer.get_number_float();
- if (JSON_HEDLEY_UNLIKELY(not std::isfinite(res)))
+ if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
}
- if (JSON_HEDLEY_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
+ if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
{
return false;
}
@@ -9881,7 +10389,7 @@
case token_type::literal_false:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->boolean(false)))
+ if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
{
return false;
}
@@ -9890,7 +10398,7 @@
case token_type::literal_null:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->null()))
+ if (JSON_HEDLEY_UNLIKELY(!sax->null()))
{
return false;
}
@@ -9899,7 +10407,7 @@
case token_type::literal_true:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->boolean(true)))
+ if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
{
return false;
}
@@ -9908,7 +10416,7 @@
case token_type::value_integer:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
+ if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))
{
return false;
}
@@ -9917,7 +10425,7 @@
case token_type::value_string:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->string(m_lexer.get_string())))
+ if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))
{
return false;
}
@@ -9926,7 +10434,7 @@
case token_type::value_unsigned:
{
- if (JSON_HEDLEY_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
+ if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))
{
return false;
}
@@ -9976,7 +10484,7 @@
// closing ]
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
{
- if (JSON_HEDLEY_UNLIKELY(not sax->end_array()))
+ if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
{
return false;
}
@@ -9985,7 +10493,7 @@
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
- assert(not states.empty());
+ JSON_ASSERT(!states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
@@ -10010,7 +10518,7 @@
exception_message(token_type::value_string, "object key")));
}
- if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string())))
+ if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
{
return false;
}
@@ -10032,7 +10540,7 @@
// closing }
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
{
- if (JSON_HEDLEY_UNLIKELY(not sax->end_object()))
+ if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
{
return false;
}
@@ -10041,7 +10549,7 @@
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
- assert(not states.empty());
+ JSON_ASSERT(!states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
@@ -10065,7 +10573,7 @@
{
std::string error_msg = "syntax error ";
- if (not context.empty())
+ if (!context.empty())
{
error_msg += "while parsing " + context + " ";
}
@@ -10245,8 +10753,6 @@
typename BasicJsonType::object_t::iterator object_iterator {};
/// iterator for JSON arrays
typename BasicJsonType::array_t::iterator array_iterator {};
- /// iterator for JSON binary arrays
- typename BasicJsonType::binary_t::container_type::iterator binary_iterator {};
/// generic iterator for all other types
primitive_iterator_t primitive_iterator {};
};
@@ -10259,8 +10765,6 @@
#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
#include <type_traits> // conditional, is_const, remove_const
-// #include <nlohmann/detail/boolean_operators.hpp>
-
// #include <nlohmann/detail/exceptions.hpp>
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
@@ -10349,7 +10853,7 @@
*/
explicit iter_impl(pointer object) noexcept : m_object(object)
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10435,7 +10939,7 @@
*/
void set_begin() noexcept
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10472,7 +10976,7 @@
*/
void set_end() noexcept
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10503,19 +11007,19 @@
*/
reference operator*() const
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
case value_t::object:
{
- assert(m_it.object_iterator != m_object->m_value.object->end());
+ JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
return m_it.object_iterator->second;
}
case value_t::array:
{
- assert(m_it.array_iterator != m_object->m_value.array->end());
+ JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
return *m_it.array_iterator;
}
@@ -10540,19 +11044,19 @@
*/
pointer operator->() const
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
case value_t::object:
{
- assert(m_it.object_iterator != m_object->m_value.object->end());
+ JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
return &(m_it.object_iterator->second);
}
case value_t::array:
{
- assert(m_it.array_iterator != m_object->m_value.array->end());
+ JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
return &*m_it.array_iterator;
}
@@ -10585,7 +11089,7 @@
*/
iter_impl& operator++()
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10628,7 +11132,7 @@
*/
iter_impl& operator--()
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10666,7 +11170,7 @@
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
}
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10687,7 +11191,7 @@
*/
bool operator!=(const iter_impl& other) const
{
- return not operator==(other);
+ return !operator==(other);
}
/*!
@@ -10702,7 +11206,7 @@
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
}
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10723,7 +11227,7 @@
*/
bool operator<=(const iter_impl& other) const
{
- return not other.operator < (*this);
+ return !other.operator < (*this);
}
/*!
@@ -10732,7 +11236,7 @@
*/
bool operator>(const iter_impl& other) const
{
- return not operator<=(other);
+ return !operator<=(other);
}
/*!
@@ -10741,7 +11245,7 @@
*/
bool operator>=(const iter_impl& other) const
{
- return not operator<(other);
+ return !operator<(other);
}
/*!
@@ -10750,7 +11254,7 @@
*/
iter_impl& operator+=(difference_type i)
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10821,7 +11325,7 @@
*/
difference_type operator-(const iter_impl& other) const
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10842,7 +11346,7 @@
*/
reference operator[](difference_type n) const
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@@ -10873,7 +11377,7 @@
*/
const typename object_t::key_type& key() const
{
- assert(m_object != nullptr);
+ JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->is_object()))
{
@@ -11030,8 +11534,8 @@
#include <algorithm> // all_of
-#include <cassert> // assert
#include <cctype> // isdigit
+#include <limits> // max
#include <numeric> // accumulate
#include <string> // string
#include <utility> // move
@@ -11357,12 +11861,17 @@
@return integer representation of @a s
+ @throw parse_error.106 if an array index begins with '0'
+ @throw parse_error.109 if an array index begins not with a digit
@throw out_of_range.404 if string @a s could not be converted to an integer
+ @throw out_of_range.410 if an array index exceeds size_type
*/
- static int array_index(const std::string& s)
+ static typename BasicJsonType::size_type array_index(const std::string& s)
{
+ using size_type = typename BasicJsonType::size_type;
+
// error condition (cf. RFC 6901, Sect. 4)
- if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and s[0] == '0'))
+ if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
{
JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + s +
@@ -11370,16 +11879,16 @@
}
// error condition (cf. RFC 6901, Sect. 4)
- if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and not (s[0] >= '1' and s[0] <= '9')))
+ if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
{
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number"));
}
std::size_t processed_chars = 0;
- int res = 0;
+ unsigned long long res = 0;
JSON_TRY
{
- res = std::stoi(s, &processed_chars);
+ res = std::stoull(s, &processed_chars);
}
JSON_CATCH(std::out_of_range&)
{
@@ -11392,7 +11901,14 @@
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'"));
}
- return res;
+ // only triggered on special platforms (like 32bit), see also
+ // https://github.com/nlohmann/json/pull/2203
+ if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))
+ {
+ JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type")); // LCOV_EXCL_LINE
+ }
+
+ return static_cast<size_type>(res);
}
json_pointer top() const
@@ -11417,7 +11933,6 @@
*/
BasicJsonType& get_and_create(BasicJsonType& j) const
{
- using size_type = typename BasicJsonType::size_type;
auto result = &j;
// in case no reference tokens exist, return a reference to the JSON value
@@ -11451,7 +11966,7 @@
case detail::value_t::array:
{
// create an entry in the array
- result = &result->operator[](static_cast<size_type>(array_index(reference_token)));
+ result = &result->operator[](array_index(reference_token));
break;
}
@@ -11490,7 +12005,6 @@
*/
BasicJsonType& get_unchecked(BasicJsonType* ptr) const
{
- using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
// convert null values to arrays or objects before continuing
@@ -11505,7 +12019,7 @@
});
// change value to array for numbers or "-" or to object otherwise
- *ptr = (nums or reference_token == "-")
+ *ptr = (nums || reference_token == "-")
? detail::value_t::array
: detail::value_t::object;
}
@@ -11529,8 +12043,7 @@
else
{
// convert array index to number; unchecked access
- ptr = &ptr->operator[](
- static_cast<size_type>(array_index(reference_token)));
+ ptr = &ptr->operator[](array_index(reference_token));
}
break;
}
@@ -11551,7 +12064,6 @@
*/
BasicJsonType& get_checked(BasicJsonType* ptr) const
{
- using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
@@ -11574,7 +12086,7 @@
}
// note: at performs range check
- ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
+ ptr = &ptr->at(array_index(reference_token));
break;
}
@@ -11601,7 +12113,6 @@
*/
const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
{
- using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
@@ -11624,8 +12135,7 @@
}
// use unchecked array access
- ptr = &ptr->operator[](
- static_cast<size_type>(array_index(reference_token)));
+ ptr = &ptr->operator[](array_index(reference_token));
break;
}
@@ -11645,7 +12155,6 @@
*/
const BasicJsonType& get_checked(const BasicJsonType* ptr) const
{
- using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
@@ -11668,7 +12177,7 @@
}
// note: at performs range check
- ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
+ ptr = &ptr->at(array_index(reference_token));
break;
}
@@ -11686,14 +12195,13 @@
*/
bool contains(const BasicJsonType* ptr) const
{
- using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
{
case detail::value_t::object:
{
- if (not ptr->contains(reference_token))
+ if (!ptr->contains(reference_token))
{
// we did not find the key in the object
return false;
@@ -11710,21 +12218,21 @@
// "-" always fails the range check
return false;
}
- if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 and not ("0" <= reference_token and reference_token <= "9")))
+ if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
{
// invalid char
return false;
}
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
{
- if (JSON_HEDLEY_UNLIKELY(not ('1' <= reference_token[0] and reference_token[0] <= '9')))
+ if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
{
// first char should be between '1' and '9'
return false;
}
for (std::size_t i = 1; i < reference_token.size(); i++)
{
- if (JSON_HEDLEY_UNLIKELY(not ('0' <= reference_token[i] and reference_token[i] <= '9')))
+ if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
{
// other char should be between '0' and '9'
return false;
@@ -11732,7 +12240,7 @@
}
}
- const auto idx = static_cast<size_type>(array_index(reference_token));
+ const auto idx = array_index(reference_token);
if (idx >= ptr->size())
{
// index out of range
@@ -11808,11 +12316,11 @@
pos != std::string::npos;
pos = reference_token.find_first_of('~', pos + 1))
{
- assert(reference_token[pos] == '~');
+ JSON_ASSERT(reference_token[pos] == '~');
// ~ must be followed by 0 or 1
- if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or
- (reference_token[pos + 1] != '0' and
+ if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
+ (reference_token[pos + 1] != '0' &&
reference_token[pos + 1] != '1')))
{
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
@@ -11843,7 +12351,7 @@
static void replace_substring(std::string& s, const std::string& f,
const std::string& t)
{
- assert(not f.empty());
+ JSON_ASSERT(!f.empty());
for (auto pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t, and
@@ -11938,7 +12446,7 @@
static BasicJsonType
unflatten(const BasicJsonType& value)
{
- if (JSON_HEDLEY_UNLIKELY(not value.is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
{
JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
}
@@ -11948,7 +12456,7 @@
// iterate the JSON object values
for (const auto& element : *value.m_value.object)
{
- if (JSON_HEDLEY_UNLIKELY(not element.second.is_primitive()))
+ if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
{
JSON_THROW(detail::type_error::create(315, "values in object must be primitive"));
}
@@ -11994,7 +12502,7 @@
friend bool operator!=(json_pointer const& lhs,
json_pointer const& rhs) noexcept
{
- return not (lhs == rhs);
+ return !(lhs == rhs);
}
/// the reference tokens
@@ -12022,23 +12530,30 @@
using value_type = BasicJsonType;
json_ref(value_type&& value)
- : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)
+ : owned_value(std::move(value))
+ , value_ref(&owned_value)
+ , is_rvalue(true)
{}
json_ref(const value_type& value)
- : value_ref(const_cast<value_type*>(&value)), is_rvalue(false)
+ : value_ref(const_cast<value_type*>(&value))
+ , is_rvalue(false)
{}
json_ref(std::initializer_list<json_ref> init)
- : owned_value(init), value_ref(&owned_value), is_rvalue(true)
+ : owned_value(init)
+ , value_ref(&owned_value)
+ , is_rvalue(true)
{}
template <
class... Args,
enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
json_ref(Args && ... args)
- : owned_value(std::forward<Args>(args)...), value_ref(&owned_value),
- is_rvalue(true) {}
+ : owned_value(std::forward<Args>(args)...)
+ , value_ref(&owned_value)
+ , is_rvalue(true)
+ {}
// class should be movable only
json_ref(json_ref&&) = default;
@@ -12069,7 +12584,7 @@
private:
mutable value_type owned_value = nullptr;
value_type* value_ref = nullptr;
- const bool is_rvalue;
+ const bool is_rvalue = true;
};
} // namespace detail
} // namespace nlohmann
@@ -12238,6 +12753,7 @@
{
using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t;
+ using number_float_t = typename BasicJsonType::number_float_t;
public:
/*!
@@ -12247,7 +12763,7 @@
*/
explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
{
- assert(oa);
+ JSON_ASSERT(oa);
}
/*!
@@ -12404,18 +12920,7 @@
}
else
{
- if (static_cast<double>(j.m_value.number_float) >= static_cast<double>(std::numeric_limits<float>::lowest()) and
- static_cast<double>(j.m_value.number_float) <= static_cast<double>((std::numeric_limits<float>::max)()) and
- static_cast<double>(static_cast<float>(j.m_value.number_float)) == static_cast<double>(j.m_value.number_float))
- {
- oa->write_character(get_cbor_float_prefix(static_cast<float>(j.m_value.number_float)));
- write_number(static_cast<float>(j.m_value.number_float));
- }
- else
- {
- oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
- write_number(j.m_value.number_float);
- }
+ write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);
}
break;
}
@@ -12499,6 +13004,12 @@
case value_t::binary:
{
+ if (j.m_value.binary->has_subtype())
+ {
+ write_number(static_cast<std::uint8_t>(0xd8));
+ write_number(j.m_value.binary->subtype());
+ }
+
// step 1: write control byte and the binary array size
const auto N = j.m_value.binary->size();
if (N <= 0x17)
@@ -12646,28 +13157,28 @@
// negative fixnum
write_number(static_cast<std::int8_t>(j.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and
+ else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{
// int 8
oa->write_character(to_char_type(0xD0));
write_number(static_cast<std::int8_t>(j.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and
+ else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{
// int 16
oa->write_character(to_char_type(0xD1));
write_number(static_cast<std::int16_t>(j.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and
+ else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{
// int 32
oa->write_character(to_char_type(0xD2));
write_number(static_cast<std::int32_t>(j.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and
+ else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{
// int 64
@@ -12714,8 +13225,7 @@
case value_t::number_float:
{
- oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
- write_number(j.m_value.number_float);
+ write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);
break;
}
@@ -12794,7 +13304,7 @@
const auto N = j.m_value.binary->size();
if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
- std::uint8_t output_type;
+ std::uint8_t output_type{};
bool fixed = true;
if (use_ext)
{
@@ -12829,37 +13339,25 @@
}
oa->write_character(to_char_type(output_type));
- if (not fixed)
+ if (!fixed)
{
write_number(static_cast<std::uint8_t>(N));
}
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
- std::uint8_t output_type;
- if (use_ext)
- {
- output_type = 0xC8; // ext 16
- }
- else
- {
- output_type = 0xC5; // bin 16
- }
+ std::uint8_t output_type = use_ext
+ ? 0xC8 // ext 16
+ : 0xC5; // bin 16
oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint16_t>(N));
}
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{
- std::uint8_t output_type;
- if (use_ext)
- {
- output_type = 0xC9; // ext 32
- }
- else
- {
- output_type = 0xC6; // bin 32
- }
+ std::uint8_t output_type = use_ext
+ ? 0xC9 // ext 32
+ : 0xC6; // bin 32
oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint32_t>(N));
@@ -12985,9 +13483,9 @@
}
bool prefix_required = true;
- if (use_type and not j.m_value.array->empty())
+ if (use_type && !j.m_value.array->empty())
{
- assert(use_count);
+ JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
[this, first_prefix](const BasicJsonType & v)
@@ -13014,7 +13512,7 @@
write_ubjson(el, use_count, use_type, prefix_required);
}
- if (not use_count)
+ if (!use_count)
{
oa->write_character(to_char_type(']'));
}
@@ -13029,9 +13527,9 @@
oa->write_character(to_char_type('['));
}
- if (use_type and not j.m_value.binary->empty())
+ if (use_type && !j.m_value.binary->empty())
{
- assert(use_count);
+ JSON_ASSERT(use_count);
oa->write_character(to_char_type('$'));
oa->write_character('U');
}
@@ -13057,7 +13555,7 @@
}
}
- if (not use_count)
+ if (!use_count)
{
oa->write_character(to_char_type(']'));
}
@@ -13073,9 +13571,9 @@
}
bool prefix_required = true;
- if (use_type and not j.m_value.object->empty())
+ if (use_type && !j.m_value.object->empty())
{
- assert(use_count);
+ JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin(), j.end(),
[this, first_prefix](const BasicJsonType & v)
@@ -13106,7 +13604,7 @@
write_ubjson(el.second, use_count, use_type, prefix_required);
}
- if (not use_count)
+ if (!use_count)
{
oa->write_character(to_char_type('}'));
}
@@ -13207,7 +13705,7 @@
*/
static std::size_t calc_bson_integer_size(const std::int64_t value)
{
- return (std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()
+ return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
? sizeof(std::int32_t)
: sizeof(std::int64_t);
}
@@ -13218,7 +13716,7 @@
void write_bson_integer(const string_t& name,
const std::int64_t value)
{
- if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
+ if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
{
write_bson_entry_header(name, 0x10); // int32
write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
@@ -13367,7 +13865,7 @@
// LCOV_EXCL_START
default:
- assert(false);
+ JSON_ASSERT(false);
return 0ul;
// LCOV_EXCL_STOP
}
@@ -13414,7 +13912,7 @@
// LCOV_EXCL_START
default:
- assert(false);
+ JSON_ASSERT(false);
return;
// LCOV_EXCL_STOP
}
@@ -13546,18 +14044,28 @@
}
else
{
- JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64"));
+ if (add_prefix)
+ {
+ oa->write_character(to_char_type('H')); // high-precision number
+ }
+
+ const auto number = BasicJsonType(n).dump();
+ write_number_with_ubjson_prefix(number.size(), true);
+ for (std::size_t i = 0; i < number.size(); ++i)
+ {
+ oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
+ }
}
}
// UBJSON: write number (signed integer)
- template<typename NumberType, typename std::enable_if<
- std::is_signed<NumberType>::value and
- not std::is_floating_point<NumberType>::value, int>::type = 0>
+ template < typename NumberType, typename std::enable_if <
+ std::is_signed<NumberType>::value&&
+ !std::is_floating_point<NumberType>::value, int >::type = 0 >
void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix)
{
- if ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)())
+ if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
{
if (add_prefix)
{
@@ -13565,7 +14073,7 @@
}
write_number(static_cast<std::int8_t>(n));
}
- else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n and n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
+ else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
{
if (add_prefix)
{
@@ -13573,7 +14081,7 @@
}
write_number(static_cast<std::uint8_t>(n));
}
- else if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)())
+ else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
{
if (add_prefix)
{
@@ -13581,7 +14089,7 @@
}
write_number(static_cast<std::int16_t>(n));
}
- else if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)())
+ else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
{
if (add_prefix)
{
@@ -13589,7 +14097,7 @@
}
write_number(static_cast<std::int32_t>(n));
}
- else if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)())
+ else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
{
if (add_prefix)
{
@@ -13600,19 +14108,23 @@
// LCOV_EXCL_START
else
{
- JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64"));
+ if (add_prefix)
+ {
+ oa->write_character(to_char_type('H')); // high-precision number
+ }
+
+ const auto number = BasicJsonType(n).dump();
+ write_number_with_ubjson_prefix(number.size(), true);
+ for (std::size_t i = 0; i < number.size(); ++i)
+ {
+ oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
+ }
}
// LCOV_EXCL_STOP
}
/*!
@brief determine the type prefix of container values
-
- @note This function does not need to be 100% accurate when it comes to
- integer limits. In case a number exceeds the limits of int64_t,
- this will be detected by a later call to function
- write_number_with_ubjson_prefix. Therefore, we return 'L' for any
- value that does not fit the previous limits.
*/
CharType ubjson_prefix(const BasicJsonType& j) const noexcept
{
@@ -13626,24 +14138,28 @@
case value_t::number_integer:
{
- if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
+ if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{
return 'i';
}
- if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
+ if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{
return 'U';
}
- if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
+ if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{
return 'I';
}
- if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
+ if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{
return 'l';
}
- // no check and assume int64_t (see note above)
- return 'L';
+ if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
+ {
+ return 'L';
+ }
+ // anything else is treated as high-precision number
+ return 'H'; // LCOV_EXCL_LINE
}
case value_t::number_unsigned:
@@ -13664,8 +14180,12 @@
{
return 'l';
}
- // no check and assume int64_t (see note above)
- return 'L';
+ if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+ {
+ return 'L';
+ }
+ // anything else is treated as high-precision number
+ return 'H'; // LCOV_EXCL_LINE
}
case value_t::number_float:
@@ -13728,20 +14248,40 @@
oa->write_characters(vec.data(), sizeof(NumberType));
}
+ void write_compact_float(const number_float_t n, detail::input_format_t format)
+ {
+ if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
+ static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
+ static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
+ {
+ oa->write_character(format == detail::input_format_t::cbor
+ ? get_cbor_float_prefix(static_cast<float>(n))
+ : get_msgpack_float_prefix(static_cast<float>(n)));
+ write_number(static_cast<float>(n));
+ }
+ else
+ {
+ oa->write_character(format == detail::input_format_t::cbor
+ ? get_cbor_float_prefix(n)
+ : get_msgpack_float_prefix(n));
+ write_number(n);
+ }
+ }
+
public:
// The following to_char_type functions are implement the conversion
// between uint8_t and CharType. In case CharType is not unsigned,
// such a conversion is required to allow values greater than 128.
// See <https://github.com/nlohmann/json/issues/1286> for a discussion.
template < typename C = CharType,
- enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >
+ enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
static constexpr CharType to_char_type(std::uint8_t x) noexcept
{
return *reinterpret_cast<char*>(&x);
}
template < typename C = CharType,
- enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >
+ enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
static CharType to_char_type(std::uint8_t x) noexcept
{
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
@@ -13760,8 +14300,8 @@
template < typename InputCharType, typename C = CharType,
enable_if_t <
- std::is_signed<C>::value and
- std::is_signed<char>::value and
+ std::is_signed<C>::value &&
+ std::is_signed<char>::value &&
std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
> * = nullptr >
static constexpr CharType to_char_type(InputCharType x) noexcept
@@ -13786,32 +14326,26 @@
#include <algorithm> // reverse, remove, fill, find, none_of
#include <array> // array
-#include <cassert> // assert
#include <clocale> // localeconv, lconv
#include <cmath> // labs, isfinite, isnan, signbit
#include <cstddef> // size_t, ptrdiff_t
#include <cstdint> // uint8_t
#include <cstdio> // snprintf
#include <limits> // numeric_limits
-#include <string> // string
+#include <string> // string, char_traits
#include <type_traits> // is_same
#include <utility> // move
-// #include <nlohmann/detail/boolean_operators.hpp>
-
// #include <nlohmann/detail/conversions/to_chars.hpp>
#include <array> // array
-#include <cassert> // assert
#include <cmath> // signbit, isfinite
#include <cstdint> // intN_t, uintN_t
#include <cstring> // memcpy, memmove
#include <limits> // numeric_limits
#include <type_traits> // conditional
-// #include <nlohmann/detail/boolean_operators.hpp>
-
// #include <nlohmann/detail/macro_scope.hpp>
@@ -13842,7 +14376,7 @@
namespace dtoa_impl
{
-template <typename Target, typename Source>
+template<typename Target, typename Source>
Target reinterpret_bits(const Source source)
{
static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
@@ -13867,8 +14401,8 @@
*/
static diyfp sub(const diyfp& x, const diyfp& y) noexcept
{
- assert(x.e == y.e);
- assert(x.f >= y.f);
+ JSON_ASSERT(x.e == y.e);
+ JSON_ASSERT(x.f >= y.f);
return {x.f - y.f, x.e};
}
@@ -13944,7 +14478,7 @@
*/
static diyfp normalize(diyfp x) noexcept
{
- assert(x.f != 0);
+ JSON_ASSERT(x.f != 0);
while ((x.f >> 63u) == 0)
{
@@ -13963,8 +14497,8 @@
{
const int delta = x.e - target_exponent;
- assert(delta >= 0);
- assert(((x.f << delta) >> delta) == x.f);
+ JSON_ASSERT(delta >= 0);
+ JSON_ASSERT(((x.f << delta) >> delta) == x.f);
return {x.f << delta, target_exponent};
}
@@ -13983,11 +14517,11 @@
@pre value must be finite and positive
*/
-template <typename FloatType>
+template<typename FloatType>
boundaries compute_boundaries(FloatType value)
{
- assert(std::isfinite(value));
- assert(value > 0);
+ JSON_ASSERT(std::isfinite(value));
+ JSON_ASSERT(value > 0);
// Convert the IEEE representation into a diyfp.
//
@@ -14036,7 +14570,7 @@
// -----------------+------+------+-------------+-------------+--- (B)
// v- m- v m+ v+
- const bool lower_boundary_is_closer = F == 0 and E > 1;
+ const bool lower_boundary_is_closer = F == 0 && E > 1;
const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
const diyfp m_minus = lower_boundary_is_closer
? diyfp(4 * v.f - 1, v.e - 2) // (B)
@@ -14267,18 +14801,18 @@
// k = ceil((kAlpha - e - 1) * 0.30102999566398114)
// for |e| <= 1500, but doesn't require floating-point operations.
// NB: log_10(2) ~= 78913 / 2^18
- assert(e >= -1500);
- assert(e <= 1500);
+ JSON_ASSERT(e >= -1500);
+ JSON_ASSERT(e <= 1500);
const int f = kAlpha - e - 1;
const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
- assert(index >= 0);
- assert(static_cast<std::size_t>(index) < kCachedPowers.size());
+ JSON_ASSERT(index >= 0);
+ JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
- assert(kAlpha <= cached.e + e + 64);
- assert(kGamma >= cached.e + e + 64);
+ JSON_ASSERT(kAlpha <= cached.e + e + 64);
+ JSON_ASSERT(kGamma >= cached.e + e + 64);
return cached;
}
@@ -14346,10 +14880,10 @@
inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
std::uint64_t rest, std::uint64_t ten_k)
{
- assert(len >= 1);
- assert(dist <= delta);
- assert(rest <= delta);
- assert(ten_k > 0);
+ JSON_ASSERT(len >= 1);
+ JSON_ASSERT(dist <= delta);
+ JSON_ASSERT(rest <= delta);
+ JSON_ASSERT(ten_k > 0);
// <--------------------------- delta ---->
// <---- dist --------->
@@ -14371,10 +14905,10 @@
// integer arithmetic.
while (rest < dist
- and delta - rest >= ten_k
- and (rest + ten_k < dist or dist - rest > rest + ten_k - dist))
+ && delta - rest >= ten_k
+ && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
{
- assert(buf[len - 1] != '0');
+ JSON_ASSERT(buf[len - 1] != '0');
buf[len - 1]--;
rest += ten_k;
}
@@ -14402,8 +14936,8 @@
// Grisu2 generates the digits of M+ from left to right and stops as soon as
// V is in [M-,M+].
- assert(M_plus.e >= kAlpha);
- assert(M_plus.e <= kGamma);
+ JSON_ASSERT(M_plus.e >= kAlpha);
+ JSON_ASSERT(M_plus.e <= kGamma);
std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e)
@@ -14424,7 +14958,7 @@
//
// Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
- assert(p1 > 0);
+ JSON_ASSERT(p1 > 0);
std::uint32_t pow10;
const int k = find_largest_pow10(p1, pow10);
@@ -14460,7 +14994,7 @@
// M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
//
- assert(d <= 9);
+ JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
//
// M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
@@ -14547,7 +15081,7 @@
//
// and stop as soon as 10^-m * r * 2^e <= delta * 2^e
- assert(p2 > delta);
+ JSON_ASSERT(p2 > delta);
int m = 0;
for (;;)
@@ -14558,7 +15092,7 @@
// = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
//
- assert(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
+ JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
p2 *= 10;
const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e
const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
@@ -14567,7 +15101,7 @@
// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
//
- assert(d <= 9);
+ JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
//
// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
@@ -14628,8 +15162,8 @@
inline void grisu2(char* buf, int& len, int& decimal_exponent,
diyfp m_minus, diyfp v, diyfp m_plus)
{
- assert(m_plus.e == m_minus.e);
- assert(m_plus.e == v.e);
+ JSON_ASSERT(m_plus.e == m_minus.e);
+ JSON_ASSERT(m_plus.e == v.e);
// --------(-----------------------+-----------------------)-------- (A)
// m- v m+
@@ -14683,15 +15217,15 @@
len is the length of the buffer (number of decimal digits)
The buffer must be large enough, i.e. >= max_digits10.
*/
-template <typename FloatType>
+template<typename FloatType>
JSON_HEDLEY_NON_NULL(1)
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
{
static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
"internal error: not enough precision");
- assert(std::isfinite(value));
- assert(value > 0);
+ JSON_ASSERT(std::isfinite(value));
+ JSON_ASSERT(value > 0);
// If the neighbors (and boundaries) of 'value' are always computed for double-precision
// numbers, all float's can be recovered using strtod (and strtof). However, the resulting
@@ -14727,8 +15261,8 @@
JSON_HEDLEY_RETURNS_NON_NULL
inline char* append_exponent(char* buf, int e)
{
- assert(e > -1000);
- assert(e < 1000);
+ JSON_ASSERT(e > -1000);
+ JSON_ASSERT(e < 1000);
if (e < 0)
{
@@ -14780,8 +15314,8 @@
inline char* format_buffer(char* buf, int len, int decimal_exponent,
int min_exp, int max_exp)
{
- assert(min_exp < 0);
- assert(max_exp > 0);
+ JSON_ASSERT(min_exp < 0);
+ JSON_ASSERT(max_exp > 0);
const int k = len;
const int n = len + decimal_exponent;
@@ -14790,7 +15324,7 @@
// k is the length of the buffer (number of decimal digits)
// n is the position of the decimal point relative to the start of the buffer.
- if (k <= n and n <= max_exp)
+ if (k <= n && n <= max_exp)
{
// digits[000]
// len <= max_exp + 2
@@ -14802,19 +15336,19 @@
return buf + (static_cast<size_t>(n) + 2);
}
- if (0 < n and n <= max_exp)
+ if (0 < n && n <= max_exp)
{
// dig.its
// len <= max_digits10 + 1
- assert(k > n);
+ JSON_ASSERT(k > n);
std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
buf[n] = '.';
return buf + (static_cast<size_t>(k) + 1U);
}
- if (min_exp < n and n <= 0)
+ if (min_exp < n && n <= 0)
{
// 0.[000]digits
// len <= 2 + (-min_exp - 1) + max_digits10
@@ -14859,13 +15393,13 @@
@note The buffer must be large enough.
@note The result is NOT null-terminated.
*/
-template <typename FloatType>
+template<typename FloatType>
JSON_HEDLEY_NON_NULL(1, 2)
JSON_HEDLEY_RETURNS_NON_NULL
char* to_chars(char* first, const char* last, FloatType value)
{
static_cast<void>(last); // maybe unused - fix warning
- assert(std::isfinite(value));
+ JSON_ASSERT(std::isfinite(value));
// Use signbit(value) instead of (value < 0) since signbit works for -0.
if (std::signbit(value))
@@ -14883,7 +15417,7 @@
return first;
}
- assert(last - first >= std::numeric_limits<FloatType>::max_digits10);
+ JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
// Compute v = buffer * 10^decimal_exponent.
// The decimal digits are stored in the buffer, which needs to be interpreted
@@ -14893,16 +15427,16 @@
int decimal_exponent = 0;
dtoa_impl::grisu2(first, len, decimal_exponent, value);
- assert(len <= std::numeric_limits<FloatType>::max_digits10);
+ JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
// Format the buffer like printf("%.*g", prec, value)
constexpr int kMinExp = -4;
// Use digits10 here to increase compatibility with version 2.
constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
- assert(last - first >= kMaxExp + 2);
- assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
- assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
+ JSON_ASSERT(last - first >= kMaxExp + 2);
+ JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
+ JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
}
@@ -14960,8 +15494,8 @@
error_handler_t error_handler_ = error_handler_t::strict)
: o(std::move(s))
, loc(std::localeconv())
- , thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep))
- , decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point))
+ , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
+ , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
, indent_char(ichar)
, indent_string(512, indent_char)
, error_handler(error_handler_)
@@ -15036,8 +15570,8 @@
}
// last element
- assert(i != val.m_value.object->cend());
- assert(std::next(i) == val.m_value.object->cend());
+ JSON_ASSERT(i != val.m_value.object->cend());
+ JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_characters(indent_string.c_str(), new_indent);
o->write_character('\"');
dump_escaped(i->first, ensure_ascii);
@@ -15064,8 +15598,8 @@
}
// last element
- assert(i != val.m_value.object->cend());
- assert(std::next(i) == val.m_value.object->cend());
+ JSON_ASSERT(i != val.m_value.object->cend());
+ JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_character('\"');
dump_escaped(i->first, ensure_ascii);
o->write_characters("\":", 2);
@@ -15106,7 +15640,7 @@
}
// last element
- assert(not val.m_value.array->empty());
+ JSON_ASSERT(!val.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent);
dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
@@ -15127,7 +15661,7 @@
}
// last element
- assert(not val.m_value.array->empty());
+ JSON_ASSERT(!val.m_value.array->empty());
dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
o->write_character(']');
@@ -15161,7 +15695,7 @@
o->write_characters("\"bytes\": [", 10);
- if (not val.m_value.binary->empty())
+ if (!val.m_value.binary->empty())
{
for (auto i = val.m_value.binary->cbegin();
i != val.m_value.binary->cend() - 1; ++i)
@@ -15192,7 +15726,7 @@
{
o->write_characters("{\"bytes\":[", 10);
- if (not val.m_value.binary->empty())
+ if (!val.m_value.binary->empty())
{
for (auto i = val.m_value.binary->cbegin();
i != val.m_value.binary->cend() - 1; ++i)
@@ -15261,7 +15795,7 @@
}
default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
}
}
@@ -15353,7 +15887,7 @@
{
// escape control characters (0x00..0x1F) or, if
// ensure_ascii parameter is used, non-ASCII characters
- if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))
+ if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
{
if (codepoint <= 0xFFFF)
{
@@ -15460,14 +15994,14 @@
}
default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
}
break;
}
default: // decode found yet incomplete multi-byte code point
{
- if (not ensure_ascii)
+ if (!ensure_ascii)
{
// code point will not be escaped - copy byte to buffer
string_buffer[bytes++] = s[i];
@@ -15523,7 +16057,7 @@
}
default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
}
}
}
@@ -15571,11 +16105,11 @@
@param[in] x integer number (signed or unsigned) to dump
@tparam NumberType either @a number_integer_t or @a number_unsigned_t
*/
- template<typename NumberType, detail::enable_if_t<
- std::is_same<NumberType, number_unsigned_t>::value or
- std::is_same<NumberType, number_integer_t>::value or
- std::is_same<NumberType, binary_char_t>::value,
- int> = 0>
+ template < typename NumberType, detail::enable_if_t <
+ std::is_same<NumberType, number_unsigned_t>::value ||
+ std::is_same<NumberType, number_integer_t>::value ||
+ std::is_same<NumberType, binary_char_t>::value,
+ int > = 0 >
void dump_integer(NumberType x)
{
static constexpr std::array<std::array<char, 2>, 100> digits_to_99
@@ -15604,7 +16138,7 @@
// use a pointer to fill the buffer
auto buffer_ptr = number_buffer.begin();
- const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755
+ const bool is_negative = std::is_same<NumberType, number_integer_t>::value && !(x >= 0); // see issue #755
number_unsigned_t abs_value;
unsigned int n_chars;
@@ -15624,7 +16158,7 @@
}
// spare 1 byte for '\0'
- assert(n_chars < number_buffer.size() - 1);
+ JSON_ASSERT(n_chars < number_buffer.size() - 1);
// jump to the end to generate the string from backward
// so we later avoid reversing the result
@@ -15665,7 +16199,7 @@
void dump_float(number_float_t x)
{
// NaN / inf
- if (not std::isfinite(x))
+ if (!std::isfinite(x))
{
o->write_characters("null", 4);
return;
@@ -15677,8 +16211,8 @@
//
// NB: The test below works if <long double> == <double>.
static constexpr bool is_ieee_single_or_double
- = (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or
- (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);
+ = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
+ (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
}
@@ -15700,9 +16234,9 @@
std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
// negative value indicates an error
- assert(len > 0);
+ JSON_ASSERT(len > 0);
// check if buffer was large enough
- assert(static_cast<std::size_t>(len) < number_buffer.size());
+ JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
// erase thousands separator
if (thousands_sep != '\0')
@@ -15710,12 +16244,12 @@
const auto end = std::remove(number_buffer.begin(),
number_buffer.begin() + len, thousands_sep);
std::fill(end, number_buffer.end(), '\0');
- assert((end - number_buffer.begin()) <= len);
+ JSON_ASSERT((end - number_buffer.begin()) <= len);
len = (end - number_buffer.begin());
}
// convert decimal point to '.'
- if (decimal_point != '\0' and decimal_point != '.')
+ if (decimal_point != '\0' && decimal_point != '.')
{
const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
if (dec_pos != number_buffer.end())
@@ -15731,7 +16265,7 @@
std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
[](char c)
{
- return c == '.' or c == 'e';
+ return c == '.' || c == 'e';
});
if (value_is_int_like)
@@ -15790,7 +16324,7 @@
: (0xFFu >> type) & (byte);
std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
- assert(index < 400);
+ JSON_ASSERT(index < 400);
state = utf8d[index];
return state;
}
@@ -15802,7 +16336,7 @@
*/
number_unsigned_t remove_sign(number_unsigned_t x)
{
- assert(false); // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE
}
@@ -15817,7 +16351,7 @@
*/
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
{
- assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)());
+ JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
}
@@ -15853,6 +16387,179 @@
// #include <nlohmann/json_fwd.hpp>
+// #include <nlohmann/ordered_map.hpp>
+
+
+#include <functional> // less
+#include <memory> // allocator
+#include <utility> // pair
+#include <vector> // vector
+
+namespace nlohmann
+{
+
+/// ordered_map: a minimal map-like container that preserves insertion order
+/// for use within nlohmann::basic_json<ordered_map>
+template <class Key, class T, class IgnoredLess = std::less<Key>,
+ class Allocator = std::allocator<std::pair<const Key, T>>>
+ struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
+{
+ using key_type = Key;
+ using mapped_type = T;
+ using Container = std::vector<std::pair<const Key, T>, Allocator>;
+ using typename Container::iterator;
+ using typename Container::const_iterator;
+ using typename Container::size_type;
+ using typename Container::value_type;
+
+ // Explicit constructors instead of `using Container::Container`
+ // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
+ ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {}
+ template <class It>
+ ordered_map(It first, It last, const Allocator& alloc = Allocator())
+ : Container{first, last, alloc} {}
+ ordered_map(std::initializer_list<T> init, const Allocator& alloc = Allocator() )
+ : Container{init, alloc} {}
+
+ std::pair<iterator, bool> emplace(const key_type& key, T&& t)
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == key)
+ {
+ return {it, false};
+ }
+ }
+ Container::emplace_back(key, t);
+ return {--this->end(), true};
+ }
+
+ T& operator[](const Key& key)
+ {
+ return emplace(key, T{}).first->second;
+ }
+
+ const T& operator[](const Key& key) const
+ {
+ return at(key);
+ }
+
+ T& at(const Key& key)
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == key)
+ {
+ return it->second;
+ }
+ }
+
+ throw std::out_of_range("key not found");
+ }
+
+ const T& at(const Key& key) const
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == key)
+ {
+ return it->second;
+ }
+ }
+
+ throw std::out_of_range("key not found");
+ }
+
+ size_type erase(const Key& key)
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == key)
+ {
+ // Since we cannot move const Keys, re-construct them in place
+ for (auto next = it; ++next != this->end(); ++it)
+ {
+ it->~value_type(); // Destroy but keep allocation
+ new (&*it) value_type{std::move(*next)};
+ }
+ Container::pop_back();
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ iterator erase(iterator pos)
+ {
+ auto it = pos;
+
+ // Since we cannot move const Keys, re-construct them in place
+ for (auto next = it; ++next != this->end(); ++it)
+ {
+ it->~value_type(); // Destroy but keep allocation
+ new (&*it) value_type{std::move(*next)};
+ }
+ Container::pop_back();
+ return pos;
+ }
+
+ size_type count(const Key& key) const
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == key)
+ {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ iterator find(const Key& key)
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == key)
+ {
+ return it;
+ }
+ }
+ return Container::end();
+ }
+
+ const_iterator find(const Key& key) const
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == key)
+ {
+ return it;
+ }
+ }
+ return Container::end();
+ }
+
+ std::pair<iterator, bool> insert( value_type&& value )
+ {
+ return emplace(value.first, std::move(value.second));
+ }
+
+ std::pair<iterator, bool> insert( const value_type& value )
+ {
+ for (auto it = this->begin(); it != this->end(); ++it)
+ {
+ if (it->first == value.first)
+ {
+ return {it, false};
+ }
+ }
+ Container::push_back(value);
+ return {--this->end(), true};
+ }
+};
+
+} // namespace nlohmann
+
/*!
@brief namespace for Niels Lohmann
@@ -15977,10 +16684,12 @@
static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
InputAdapterType adapter,
detail::parser_callback_t<basic_json>cb = nullptr,
- bool allow_exceptions = true
- )
+ const bool allow_exceptions = true,
+ const bool ignore_comments = false
+ )
{
- return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter), std::move(cb), allow_exceptions);
+ return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
+ std::move(cb), allow_exceptions, ignore_comments);
}
using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
@@ -16009,6 +16718,8 @@
using json_serializer = JSONSerializer<T, SFINAE>;
/// how to treat decoding errors
using error_handler_t = detail::error_handler_t;
+ /// how to treat CBOR tags
+ using cbor_tag_handler_t = detail::cbor_tag_handler_t;
/// helper type for initializer lists of basic_json values
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
@@ -16121,7 +16832,7 @@
{
basic_json result;
- result["copyright"] = "(C) 2013-2017 Niels Lohmann";
+ result["copyright"] = "(C) 2013-2020 Niels Lohmann";
result["name"] = "JSON for Modern C++";
result["url"] = "https://github.com/nlohmann/json";
result["version"]["string"] =
@@ -16703,7 +17414,7 @@
};
std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
- assert(object != nullptr);
+ JSON_ASSERT(object != nullptr);
return object.release();
}
@@ -16829,7 +17540,7 @@
object = nullptr; // silence warning, see #821
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
{
- JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.8.0")); // LCOV_EXCL_LINE
+ JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.9.1")); // LCOV_EXCL_LINE
}
break;
}
@@ -16916,7 +17627,7 @@
}
}
- while (not stack.empty())
+ while (!stack.empty())
{
// move the last item to local variable to be processed
basic_json current_item(std::move(stack.back()));
@@ -16998,10 +17709,10 @@
*/
void assert_invariant() const noexcept
{
- assert(m_type != value_t::object or m_value.object != nullptr);
- assert(m_type != value_t::array or m_value.array != nullptr);
- assert(m_type != value_t::string or m_value.string != nullptr);
- assert(m_type != value_t::binary or m_value.binary != nullptr);
+ JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);
+ JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);
+ JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);
+ JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);
}
public:
@@ -17209,10 +17920,10 @@
@since version 2.1.0
*/
- template <typename CompatibleType,
- typename U = detail::uncvref_t<CompatibleType>,
- detail::enable_if_t<
- not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
+ template < typename CompatibleType,
+ typename U = detail::uncvref_t<CompatibleType>,
+ detail::enable_if_t <
+ !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
basic_json(CompatibleType && val) noexcept(noexcept(
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
std::forward<CompatibleType>(val))))
@@ -17247,9 +17958,9 @@
@since version 3.2.0
*/
- template <typename BasicJsonType,
- detail::enable_if_t<
- detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>
+ template < typename BasicJsonType,
+ detail::enable_if_t <
+ detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
basic_json(const BasicJsonType& val)
{
using other_boolean_t = typename BasicJsonType::boolean_t;
@@ -17294,7 +18005,7 @@
m_type = value_t::discarded;
break;
default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
}
assert_invariant();
}
@@ -17382,11 +18093,11 @@
bool is_an_object = std::all_of(init.begin(), init.end(),
[](const detail::json_ref<basic_json>& element_ref)
{
- return element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string();
+ return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string();
});
// adjust type if type deduction is not wanted
- if (not type_deduction)
+ if (!type_deduction)
{
// if array is wanted, do not create an object though possible
if (manual_type == value_t::array)
@@ -17395,7 +18106,7 @@
}
// if object is wanted but impossible, throw an exception
- if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object and not is_an_object))
+ if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
{
JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
}
@@ -17689,13 +18400,13 @@
@since version 1.0.0
*/
- template<class InputIT, typename std::enable_if<
- std::is_same<InputIT, typename basic_json_t::iterator>::value or
- std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
+ template < class InputIT, typename std::enable_if <
+ std::is_same<InputIT, typename basic_json_t::iterator>::value ||
+ std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
basic_json(InputIT first, InputIT last)
{
- assert(first.m_object != nullptr);
- assert(last.m_object != nullptr);
+ JSON_ASSERT(first.m_object != nullptr);
+ JSON_ASSERT(last.m_object != nullptr);
// make sure iterator fits the current value
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
@@ -17715,8 +18426,8 @@
case value_t::number_unsigned:
case value_t::string:
{
- if (JSON_HEDLEY_UNLIKELY(not first.m_it.primitive_iterator.is_begin()
- or not last.m_it.primitive_iterator.is_end()))
+ if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
+ || !last.m_it.primitive_iterator.is_end()))
{
JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
}
@@ -17792,9 +18503,9 @@
// other constructors and destructor //
///////////////////////////////////////
- template <typename JsonRef,
- detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
- std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
+ template<typename JsonRef,
+ detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
+ std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
/*!
@@ -17949,9 +18660,9 @@
@since version 1.0.0
*/
basic_json& operator=(basic_json other) noexcept (
- std::is_nothrow_move_constructible<value_t>::value and
- std::is_nothrow_move_assignable<value_t>::value and
- std::is_nothrow_move_constructible<json_value>::value and
+ std::is_nothrow_move_constructible<value_t>::value&&
+ std::is_nothrow_move_assignable<value_t>::value&&
+ std::is_nothrow_move_constructible<json_value>::value&&
std::is_nothrow_move_assignable<json_value>::value
)
{
@@ -18017,7 +18728,8 @@
@param[in] error_handler how to react on decoding errors; there are three
possible values: `strict` (throws and exception in case a decoding error
occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),
- and `ignore` (ignore invalid UTF-8 sequences during serialization).
+ and `ignore` (ignore invalid UTF-8 sequences during serialization; all
+ bytes are copied to the output unchanged).
@return string containing the serialization of the JSON value
@@ -18130,7 +18842,7 @@
*/
constexpr bool is_primitive() const noexcept
{
- return is_null() or is_string() or is_boolean() or is_number() or is_binary();
+ return is_null() || is_string() || is_boolean() || is_number() || is_binary();
}
/*!
@@ -18157,7 +18869,7 @@
*/
constexpr bool is_structured() const noexcept
{
- return is_array() or is_object();
+ return is_array() || is_object();
}
/*!
@@ -18231,7 +18943,7 @@
*/
constexpr bool is_number() const noexcept
{
- return is_number_integer() or is_number_float();
+ return is_number_integer() || is_number_float();
}
/*!
@@ -18260,7 +18972,7 @@
*/
constexpr bool is_number_integer() const noexcept
{
- return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
+ return m_type == value_t::number_integer || m_type == value_t::number_unsigned;
}
/*!
@@ -18641,9 +19353,9 @@
@since version 3.2.0
*/
- template<typename BasicJsonType, detail::enable_if_t<
- not std::is_same<BasicJsonType, basic_json>::value and
- detail::is_basic_json<BasicJsonType>::value, int> = 0>
+ template < typename BasicJsonType, detail::enable_if_t <
+ !std::is_same<BasicJsonType, basic_json>::value&&
+ detail::is_basic_json<BasicJsonType>::value, int > = 0 >
BasicJsonType get() const
{
return *this;
@@ -18688,19 +19400,19 @@
@since version 2.1.0
*/
- template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
- detail::enable_if_t <
- not detail::is_basic_json<ValueType>::value and
- detail::has_from_json<basic_json_t, ValueType>::value and
- not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
- int> = 0>
+ template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
+ detail::enable_if_t <
+ !detail::is_basic_json<ValueType>::value &&
+ detail::has_from_json<basic_json_t, ValueType>::value &&
+ !detail::has_non_default_from_json<basic_json_t, ValueType>::value,
+ int > = 0 >
ValueType get() const noexcept(noexcept(
JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
{
// we cannot static_assert on ValueTypeCV being non-const, because
// there is support for get<const basic_json_t>(), which is why we
// still need the uncvref
- static_assert(not std::is_reference<ValueTypeCV>::value,
+ static_assert(!std::is_reference<ValueTypeCV>::value,
"get() cannot be used with reference types, you might want to use get_ref()");
static_assert(std::is_default_constructible<ValueType>::value,
"types must be DefaultConstructible when used with get()");
@@ -18741,14 +19453,14 @@
@since version 2.1.0
*/
- template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
- detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and
- detail::has_non_default_from_json<basic_json_t, ValueType>::value,
- int> = 0>
+ template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
+ detail::enable_if_t < !std::is_same<basic_json_t, ValueType>::value &&
+ detail::has_non_default_from_json<basic_json_t, ValueType>::value,
+ int > = 0 >
ValueType get() const noexcept(noexcept(
JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
{
- static_assert(not std::is_reference<ValueTypeCV>::value,
+ static_assert(!std::is_reference<ValueTypeCV>::value,
"get() cannot be used with reference types, you might want to use get_ref()");
return JSONSerializer<ValueType>::from_json(*this);
}
@@ -18786,11 +19498,11 @@
@since version 3.3.0
*/
- template<typename ValueType,
- detail::enable_if_t <
- not detail::is_basic_json<ValueType>::value and
- detail::has_from_json<basic_json_t, ValueType>::value,
- int> = 0>
+ template < typename ValueType,
+ detail::enable_if_t <
+ !detail::is_basic_json<ValueType>::value&&
+ detail::has_from_json<basic_json_t, ValueType>::value,
+ int > = 0 >
ValueType & get_to(ValueType& v) const noexcept(noexcept(
JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
{
@@ -18798,6 +19510,18 @@
return v;
}
+ // specialization to allow to call get_to with a basic_json value
+ // see https://github.com/nlohmann/json/issues/2175
+ template<typename ValueType,
+ detail::enable_if_t <
+ detail::is_basic_json<ValueType>::value,
+ int> = 0>
+ ValueType & get_to(ValueType& v) const
+ {
+ v = *this;
+ return v;
+ }
+
template <
typename T, std::size_t N,
typename Array = T (&)[N],
@@ -18850,9 +19574,9 @@
@brief get a pointer value (implicit)
@copydoc get_ptr()
*/
- template<typename PointerType, typename std::enable_if<
- std::is_pointer<PointerType>::value and
- std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
+ template < typename PointerType, typename std::enable_if <
+ std::is_pointer<PointerType>::value&&
+ std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
{
// delegate the call to get_impl_ptr<>() const
@@ -18944,9 +19668,9 @@
@brief get a reference value (implicit)
@copydoc get_ref()
*/
- template<typename ReferenceType, typename std::enable_if<
- std::is_reference<ReferenceType>::value and
- std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
+ template < typename ReferenceType, typename std::enable_if <
+ std::is_reference<ReferenceType>::value&&
+ std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
ReferenceType get_ref() const
{
// delegate call to get_ref_impl
@@ -18983,17 +19707,17 @@
@since version 1.0.0
*/
template < typename ValueType, typename std::enable_if <
- not std::is_pointer<ValueType>::value and
- not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
- not std::is_same<ValueType, typename string_t::value_type>::value and
- not detail::is_basic_json<ValueType>::value
- and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
-#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) and _MSC_VER >= 1910 and _MSC_VER <= 1914))
- and not std::is_same<ValueType, typename std::string_view>::value
+ !std::is_pointer<ValueType>::value&&
+ !std::is_same<ValueType, detail::json_ref<basic_json>>::value&&
+ !std::is_same<ValueType, typename string_t::value_type>::value&&
+ !detail::is_basic_json<ValueType>::value
+ && !std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
+#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
+ && !std::is_same<ValueType, typename std::string_view>::value
#endif
- and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
+ && detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
, int >::type = 0 >
- operator ValueType() const
+ JSON_EXPLICIT operator ValueType() const
{
// delegate the call to get<>() const
return get<ValueType>();
@@ -19010,7 +19734,7 @@
*/
binary_t& get_binary()
{
- if (not is_binary())
+ if (!is_binary())
{
JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name())));
}
@@ -19021,7 +19745,7 @@
/// @copydoc get_binary()
const binary_t& get_binary() const
{
- if (not is_binary())
+ if (!is_binary())
{
JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name())));
}
@@ -19399,7 +20123,7 @@
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
- assert(m_value.object->find(key) != m_value.object->end());
+ JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
@@ -19491,7 +20215,7 @@
// at only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
- assert(m_value.object->find(key) != m_value.object->end());
+ JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
@@ -19548,9 +20272,10 @@
@since version 1.0.0
*/
- template<class ValueType, typename std::enable_if<
- std::is_convertible<basic_json_t, ValueType>::value
- and not std::is_same<value_t, ValueType>::value, int>::type = 0>
+ // using std::is_convertible in a std::enable_if will fail when using explicit conversions
+ template < class ValueType, typename std::enable_if <
+ detail::is_getable<basic_json_t, ValueType>::value
+ && !std::is_same<value_t, ValueType>::value, int >::type = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
{
// at only works for objects
@@ -19560,7 +20285,7 @@
const auto it = find(key);
if (it != end())
{
- return *it;
+ return it->template get<ValueType>();
}
return default_value;
@@ -19622,7 +20347,7 @@
@since version 2.0.2
*/
template<class ValueType, typename std::enable_if<
- std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
+ detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>
ValueType value(const json_pointer& ptr, const ValueType& default_value) const
{
// at only works for objects
@@ -19631,7 +20356,7 @@
// if pointer resolves a value, return it or use default value
JSON_TRY
{
- return ptr.get_checked(this);
+ return ptr.get_checked(this).template get<ValueType>();
}
JSON_INTERNAL_CATCH (out_of_range&)
{
@@ -19784,10 +20509,10 @@
@since version 1.0.0
*/
- template<class IteratorType, typename std::enable_if<
- std::is_same<IteratorType, typename basic_json_t::iterator>::value or
- std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
- = 0>
+ template < class IteratorType, typename std::enable_if <
+ std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
+ std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type
+ = 0 >
IteratorType erase(IteratorType pos)
{
// make sure iterator fits the current value
@@ -19807,7 +20532,7 @@
case value_t::string:
case value_t::binary:
{
- if (JSON_HEDLEY_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))
+ if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
{
JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
}
@@ -19897,14 +20622,14 @@
@since version 1.0.0
*/
- template<class IteratorType, typename std::enable_if<
- std::is_same<IteratorType, typename basic_json_t::iterator>::value or
- std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
- = 0>
+ template < class IteratorType, typename std::enable_if <
+ std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
+ std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type
+ = 0 >
IteratorType erase(IteratorType first, IteratorType last)
{
// make sure iterator fits the current value
- if (JSON_HEDLEY_UNLIKELY(this != first.m_object or this != last.m_object))
+ if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
{
JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
}
@@ -19920,8 +20645,8 @@
case value_t::string:
case value_t::binary:
{
- if (JSON_HEDLEY_LIKELY(not first.m_it.primitive_iterator.is_begin()
- or not last.m_it.primitive_iterator.is_end()))
+ if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
+ || !last.m_it.primitive_iterator.is_end()))
{
JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
}
@@ -20166,11 +20891,11 @@
@since version 3.6.0
*/
- template<typename KeyT, typename std::enable_if<
- not std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int>::type = 0>
+ template < typename KeyT, typename std::enable_if <
+ !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int >::type = 0 >
bool contains(KeyT && key) const
{
- return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
+ return is_object() && m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
}
/*!
@@ -20988,7 +21713,7 @@
void push_back(basic_json&& val)
{
// push_back only works for null objects or arrays
- if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array())))
+ if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
{
JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
}
@@ -21023,7 +21748,7 @@
void push_back(const basic_json& val)
{
// push_back only works for null objects or arrays
- if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array())))
+ if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
{
JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
}
@@ -21073,7 +21798,7 @@
void push_back(const typename object_t::value_type& val)
{
// push_back only works for null objects or objects
- if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_object())))
+ if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
{
JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
}
@@ -21127,7 +21852,7 @@
*/
void push_back(initializer_list_t init)
{
- if (is_object() and init.size() == 2 and (*init.begin())->is_string())
+ if (is_object() && init.size() == 2 && (*init.begin())->is_string())
{
basic_json&& key = init.begin()->moved_or_copied();
push_back(typename object_t::value_type(
@@ -21176,7 +21901,7 @@
reference emplace_back(Args&& ... args)
{
// emplace_back only works for null objects or arrays
- if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array())))
+ if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
{
JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name())));
}
@@ -21229,7 +21954,7 @@
std::pair<iterator, bool> emplace(Args&& ... args)
{
// emplace only works for null objects or arrays
- if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_object())))
+ if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
{
JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name())));
}
@@ -21259,7 +21984,7 @@
iterator insert_iterator(const_iterator pos, Args&& ... args)
{
iterator result(this);
- assert(m_value.array != nullptr);
+ JSON_ASSERT(m_value.array != nullptr);
auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);
m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
@@ -21396,7 +22121,7 @@
iterator insert(const_iterator pos, const_iterator first, const_iterator last)
{
// insert only works for arrays
- if (JSON_HEDLEY_UNLIKELY(not is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!is_array()))
{
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
}
@@ -21449,7 +22174,7 @@
iterator insert(const_iterator pos, initializer_list_t ilist)
{
// insert only works for arrays
- if (JSON_HEDLEY_UNLIKELY(not is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!is_array()))
{
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
}
@@ -21490,7 +22215,7 @@
void insert(const_iterator first, const_iterator last)
{
// insert only works for objects
- if (JSON_HEDLEY_UNLIKELY(not is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
}
@@ -21502,7 +22227,7 @@
}
// passed iterators must belong to objects
- if (JSON_HEDLEY_UNLIKELY(not first.m_object->is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
{
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
}
@@ -21539,11 +22264,11 @@
assert_invariant();
}
- if (JSON_HEDLEY_UNLIKELY(not is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
}
- if (JSON_HEDLEY_UNLIKELY(not j.is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
{
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name())));
}
@@ -21590,7 +22315,7 @@
assert_invariant();
}
- if (JSON_HEDLEY_UNLIKELY(not is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!is_object()))
{
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
}
@@ -21602,8 +22327,8 @@
}
// passed iterators must belong to objects
- if (JSON_HEDLEY_UNLIKELY(not first.m_object->is_object()
- or not last.m_object->is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()
+ || !last.m_object->is_object()))
{
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
}
@@ -21632,9 +22357,9 @@
@since version 1.0.0
*/
void swap(reference other) noexcept (
- std::is_nothrow_move_constructible<value_t>::value and
- std::is_nothrow_move_assignable<value_t>::value and
- std::is_nothrow_move_constructible<json_value>::value and
+ std::is_nothrow_move_constructible<value_t>::value&&
+ std::is_nothrow_move_assignable<value_t>::value&&
+ std::is_nothrow_move_constructible<json_value>::value&&
std::is_nothrow_move_assignable<json_value>::value
)
{
@@ -21646,6 +22371,34 @@
/*!
@brief exchanges the values
+ Exchanges the contents of the JSON value from @a left with those of @a right. Does not
+ invoke any move, copy, or swap operations on individual elements. All
+ iterators and references remain valid. The past-the-end iterator is
+ invalidated. implemented as a friend function callable via ADL.
+
+ @param[in,out] left JSON value to exchange the contents with
+ @param[in,out] right JSON value to exchange the contents with
+
+ @complexity Constant.
+
+ @liveexample{The example below shows how JSON values can be swapped with
+ `swap()`.,swap__reference}
+
+ @since version 1.0.0
+ */
+ friend void swap(reference left, reference right) noexcept (
+ std::is_nothrow_move_constructible<value_t>::value&&
+ std::is_nothrow_move_assignable<value_t>::value&&
+ std::is_nothrow_move_constructible<json_value>::value&&
+ std::is_nothrow_move_assignable<json_value>::value
+ )
+ {
+ left.swap(right);
+ }
+
+ /*!
+ @brief exchanges the values
+
Exchanges the contents of a JSON array with those of @a other. Does not
invoke any move, copy, or swap operations on individual elements. All
iterators and references remain valid. The past-the-end iterator is
@@ -21894,27 +22647,27 @@
return false;
}
}
- else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
+ else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)
{
return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
}
- else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
+ else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)
{
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
}
- else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+ else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)
{
return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
}
- else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
+ else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
}
- else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+ else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)
{
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
}
- else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
+ else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
}
@@ -21964,7 +22717,7 @@
*/
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
{
- return not (lhs == rhs);
+ return !(lhs == rhs);
}
/*!
@@ -22057,27 +22810,27 @@
return false;
}
}
- else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
+ else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)
{
return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
}
- else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
+ else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)
{
return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
}
- else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+ else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)
{
return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
}
- else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
+ else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
}
- else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
+ else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)
{
return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
}
- else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+ else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)
{
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
}
@@ -22131,7 +22884,7 @@
*/
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
{
- return not (rhs < lhs);
+ return !(rhs < lhs);
}
/*!
@@ -22177,7 +22930,7 @@
*/
friend bool operator>(const_reference lhs, const_reference rhs) noexcept
{
- return not (lhs <= rhs);
+ return !(lhs <= rhs);
}
/*!
@@ -22223,7 +22976,7 @@
*/
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
{
- return not (lhs < rhs);
+ return !(lhs < rhs);
}
/*!
@@ -22344,6 +23097,9 @@
(optional)
@param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default)
+ @param[in] ignore_comments whether comments should be ignored and treated
+ like whitespace (true) or yield a parse error (true); (optional, false by
+ default)
@return deserialized JSON value; in case of a parse error and
@a allow_exceptions set to `false`, the return value will be
@@ -22372,16 +23128,18 @@
@liveexample{The example below demonstrates the `parse()` function reading
from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
- @since version 2.0.3 (contiguous containers)
+ @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to
+ ignore comments.
*/
template<typename InputType>
JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json parse(InputType&& i,
const parser_callback_t cb = nullptr,
- const bool allow_exceptions = true)
+ const bool allow_exceptions = true,
+ const bool ignore_comments = false)
{
basic_json result;
- parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions).parse(true, result);
+ parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
return result;
}
@@ -22398,6 +23156,9 @@
(optional)
@param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default)
+ @param[in] ignore_comments whether comments should be ignored and treated
+ like whitespace (true) or yield a parse error (true); (optional, false by
+ default)
@return deserialized JSON value; in case of a parse error and
@a allow_exceptions set to `false`, the return value will be
@@ -22413,10 +23174,11 @@
static basic_json parse(IteratorType first,
IteratorType last,
const parser_callback_t cb = nullptr,
- const bool allow_exceptions = true)
+ const bool allow_exceptions = true,
+ const bool ignore_comments = false)
{
basic_json result;
- parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions).parse(true, result);
+ parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
return result;
}
@@ -22424,10 +23186,11 @@
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
static basic_json parse(detail::span_input_adapter&& i,
const parser_callback_t cb = nullptr,
- const bool allow_exceptions = true)
+ const bool allow_exceptions = true,
+ const bool ignore_comments = false)
{
basic_json result;
- parser(i.get(), cb, allow_exceptions).parse(true, result);
+ parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
return result;
}
@@ -22447,6 +23210,9 @@
iterators.
@param[in] i input to read from
+ @param[in] ignore_comments whether comments should be ignored and treated
+ like whitespace (true) or yield a parse error (true); (optional, false by
+ default)
@return Whether the input read from @a i is valid JSON.
@@ -22459,22 +23225,25 @@
from a string.,accept__string}
*/
template<typename InputType>
- static bool accept(InputType&& i)
+ static bool accept(InputType&& i,
+ const bool ignore_comments = false)
{
- return parser(detail::input_adapter(std::forward<InputType>(i))).accept(true);
+ return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
}
template<typename IteratorType>
- static bool accept(IteratorType first, IteratorType last)
+ static bool accept(IteratorType first, IteratorType last,
+ const bool ignore_comments = false)
{
- return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true);
+ return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
}
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
- static bool accept(detail::span_input_adapter&& i)
+ static bool accept(detail::span_input_adapter&& i,
+ const bool ignore_comments = false)
{
- return parser(i.get()).accept(true);
+ return parser(i.get(), nullptr, false, ignore_comments).accept(true);
}
/*!
@@ -22494,6 +23263,9 @@
@param[in,out] sax SAX event listener
@param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON)
@param[in] strict whether the input has to be consumed completely
+ @param[in] ignore_comments whether comments should be ignored and treated
+ like whitespace (true) or yield a parse error (true); (optional, false by
+ default); only applies to the JSON file format.
@return return value of the last processed SAX event
@@ -22518,11 +23290,12 @@
JSON_HEDLEY_NON_NULL(2)
static bool sax_parse(InputType&& i, SAX* sax,
input_format_t format = input_format_t::json,
- const bool strict = true)
+ const bool strict = true,
+ const bool ignore_comments = false)
{
auto ia = detail::input_adapter(std::forward<InputType>(i));
return format == input_format_t::json
- ? parser(std::move(ia)).sax_parse(sax, strict)
+ ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
}
@@ -22530,11 +23303,12 @@
JSON_HEDLEY_NON_NULL(3)
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
input_format_t format = input_format_t::json,
- const bool strict = true)
+ const bool strict = true,
+ const bool ignore_comments = false)
{
auto ia = detail::input_adapter(std::move(first), std::move(last));
return format == input_format_t::json
- ? parser(std::move(ia)).sax_parse(sax, strict)
+ ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
}
@@ -22543,11 +23317,12 @@
JSON_HEDLEY_NON_NULL(2)
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
input_format_t format = input_format_t::json,
- const bool strict = true)
+ const bool strict = true,
+ const bool ignore_comments = false)
{
auto ia = i.get();
return format == input_format_t::json
- ? parser(std::move(ia)).sax_parse(sax, strict)
+ ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
}
@@ -22749,7 +23524,6 @@
- bignum (0xC2..0xC3)
- decimal fraction (0xC4)
- bigfloat (0xC5)
- - tagged items (0xC6..0xD4, 0xD8..0xDB)
- expected conversions (0xD5..0xD7)
- simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7)
@@ -22765,7 +23539,7 @@
vector in CBOR format.,to_cbor}
@sa http://cbor.io
- @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
+ @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the
analogous deserialization
@sa @ref to_msgpack(const basic_json&) for the related MessagePack format
@sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
@@ -22821,7 +23595,8 @@
number_unsigned | 256..65535 | uint 16 | 0xCD
number_unsigned | 65536..4294967295 | uint 32 | 0xCE
number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF
- number_float | *any value* | float 64 | 0xCB
+ number_float | *any value representable by a float* | float 32 | 0xCA
+ number_float | *any value NOT representable by a float* | float 64 | 0xCB
string | *length*: 0..31 | fixstr | 0xA0..0xBF
string | *length*: 32..255 | str 8 | 0xD9
string | *length*: 256..65535 | str 16 | 0xDA
@@ -22845,9 +23620,6 @@
- arrays with more than 4294967295 elements
- objects with more than 4294967295 elements
- @note The following MessagePack types are not used in the conversion:
- - float 32 (0xCA)
-
@note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack.
@@ -22916,6 +23688,7 @@
number_unsigned | 256..32767 | int16 | `I`
number_unsigned | 32768..2147483647 | int32 | `l`
number_unsigned | 2147483648..9223372036854775807 | int64 | `L`
+ number_unsigned | 2147483649..18446744073709551615 | high-precision | `H`
number_float | *any value* | float64 | `D`
string | *with shortest length indicator* | string | `S`
array | *see notes on optimized format* | array | `[`
@@ -22926,7 +23699,6 @@
@note The following values can **not** be converted to a UBJSON value:
- strings with more than 9223372036854775807 bytes (theoretical)
- - unsigned integer numbers above 9223372036854775807
@note The following markers are not used in the conversion:
- `Z`: no-op values are not created.
@@ -23138,7 +23910,6 @@
- bignum (0xC2..0xC3)
- decimal fraction (0xC4)
- bigfloat (0xC5)
- - tagged items (0xC6..0xD4, 0xD8..0xDB)
- expected conversions (0xD5..0xD7)
- simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7)
@@ -23155,6 +23926,7 @@
(true by default)
@param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default)
+ @param[in] tag_handler how to treat CBOR tags (optional, error by default)
@return deserialized JSON value; in case of a parse error and
@a allow_exceptions set to `false`, the return value will be
@@ -23181,34 +23953,36 @@
@since version 2.0.9; parameter @a start_index since 2.1.1; changed to
consume input adapters, removed start_index parameter, and added
@a strict parameter since 3.0.0; added @a allow_exceptions parameter
- since 3.2.0
+ since 3.2.0; added @a tag_handler parameter since 3.9.0.
*/
template<typename InputType>
JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_cbor(InputType&& i,
const bool strict = true,
- const bool allow_exceptions = true)
+ const bool allow_exceptions = true,
+ const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
{
basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
auto ia = detail::input_adapter(std::forward<InputType>(i));
- const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict);
+ const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
return res ? result : basic_json(value_t::discarded);
}
/*!
- @copydoc from_cbor(detail::input_adapter&&, const bool, const bool)
+ @copydoc from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t)
*/
template<typename IteratorType>
JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_cbor(IteratorType first, IteratorType last,
const bool strict = true,
- const bool allow_exceptions = true)
+ const bool allow_exceptions = true,
+ const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
{
basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
auto ia = detail::input_adapter(std::move(first), std::move(last));
- const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict);
+ const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
return res ? result : basic_json(value_t::discarded);
}
@@ -23217,9 +23991,10 @@
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
static basic_json from_cbor(const T* ptr, std::size_t len,
const bool strict = true,
- const bool allow_exceptions = true)
+ const bool allow_exceptions = true,
+ const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
{
- return from_cbor(ptr, ptr + len, strict, allow_exceptions);
+ return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
}
@@ -23227,12 +24002,13 @@
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
static basic_json from_cbor(detail::span_input_adapter&& i,
const bool strict = true,
- const bool allow_exceptions = true)
+ const bool allow_exceptions = true,
+ const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
{
basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
auto ia = i.get();
- const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict);
+ const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
return res ? result : basic_json(value_t::discarded);
}
@@ -23310,7 +24086,7 @@
@sa http://msgpack.org
@sa @ref to_msgpack(const basic_json&) for the analogous serialization
- @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
+ @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the
related CBOR format
@sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for
the related UBJSON format
@@ -23397,6 +24173,7 @@
int16 | number_integer | `I`
int32 | number_integer | `l`
int64 | number_integer | `L`
+ high-precision number | number_integer, number_unsigned, or number_float - depends on number string | 'H'
string | string | `S`
char | string | `C`
array | array (optimized values are supported) | `[`
@@ -23428,7 +24205,7 @@
@sa http://ubjson.org
@sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
analogous serialization
- @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
+ @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the
related CBOR format
@sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for
the related MessagePack format
@@ -23543,7 +24320,7 @@
@sa http://bsonspec.org/spec.html
@sa @ref to_bson(const basic_json&) for the analogous serialization
- @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
+ @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the
related CBOR format
@sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for
the related MessagePack format
@@ -23962,7 +24739,7 @@
else
{
const auto idx = json_pointer::array_index(last_path);
- if (JSON_HEDLEY_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
+ if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
{
// avoid undefined behavior
JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
@@ -23976,7 +24753,7 @@
// if there exists a parent it cannot be primitive
default: // LCOV_EXCL_LINE
- assert(false); // LCOV_EXCL_LINE
+ JSON_ASSERT(false); // LCOV_EXCL_LINE
}
};
@@ -24005,12 +24782,12 @@
else if (parent.is_array())
{
// note erase performs range check
- parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));
+ parent.erase(json_pointer::array_index(last_path));
}
};
// type check: top level value must be an array
- if (JSON_HEDLEY_UNLIKELY(not json_patch.is_array()))
+ if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
{
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
}
@@ -24036,7 +24813,7 @@
}
// check if result is of type string
- if (JSON_HEDLEY_UNLIKELY(string_type and not it->second.is_string()))
+ if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
{
JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'"));
}
@@ -24046,14 +24823,14 @@
};
// type check: every element of the array must be an object
- if (JSON_HEDLEY_UNLIKELY(not val.is_object()))
+ if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
{
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
}
// collect mandatory members
- const std::string op = get_value("op", "op", true);
- const std::string path = get_value(op, "path", true);
+ const auto op = get_value("op", "op", true).template get<std::string>();
+ const auto path = get_value(op, "path", true).template get<std::string>();
json_pointer ptr(path);
switch (get_op(op))
@@ -24079,7 +24856,7 @@
case patch_operations::move:
{
- const std::string from_path = get_value("move", "from", true);
+ const auto from_path = get_value("move", "from", true).template get<std::string>();
json_pointer from_ptr(from_path);
// the "from" location must exist - use at()
@@ -24096,7 +24873,7 @@
case patch_operations::copy:
{
- const std::string from_path = get_value("copy", "from", true);
+ const auto from_path = get_value("copy", "from", true).template get<std::string>();
const json_pointer from_ptr(from_path);
// the "from" location must exist - use at()
@@ -24124,7 +24901,7 @@
}
// throw an exception if test fails
- if (JSON_HEDLEY_UNLIKELY(not success))
+ if (JSON_HEDLEY_UNLIKELY(!success))
{
JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump()));
}
@@ -24206,7 +24983,7 @@
{
// first pass: traverse common elements
std::size_t i = 0;
- while (i < source.size() and i < target.size())
+ while (i < source.size() && i < target.size())
{
// recursive call to compare array values at index i
auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
@@ -24357,7 +25134,7 @@
{
if (apply_patch.is_object())
{
- if (not is_object())
+ if (!is_object())
{
*this = object();
}
@@ -24417,9 +25194,7 @@
*/
std::size_t operator()(const nlohmann::json& j) const
{
- // a naive hashing via the string representation
- const auto& h = hash<nlohmann::json::string_t>();
- return h(j.dump());
+ return nlohmann::detail::hash(j);
}
};
@@ -24440,6 +25215,9 @@
}
};
+// C++20 prohibit function specialization in the std namespace.
+#ifndef JSON_HAS_CPP_20
+
/*!
@brief exchanges the values of two JSON objects
@@ -24447,13 +25225,15 @@
*/
template<>
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
- is_nothrow_move_constructible<nlohmann::json>::value and
+ is_nothrow_move_constructible<nlohmann::json>::value&&
is_nothrow_move_assignable<nlohmann::json>::value
-)
+ )
{
j1.swap(j2);
}
+#endif
+
} // namespace std
/*!
@@ -24506,6 +25286,7 @@
#endif
// clean up
+#undef JSON_ASSERT
#undef JSON_INTERNAL_CATCH
#undef JSON_CATCH
#undef JSON_THROW
@@ -24514,6 +25295,7 @@
#undef JSON_HAS_CPP_17
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
#undef NLOHMANN_BASIC_JSON_TPL
+#undef JSON_EXPLICIT
// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
#undef JSON_HEDLEY_ALWAYS_INLINE