From 59aef02010083c3fcf9bc53e8268ef6da454e792 Mon Sep 17 00:00:00 2001 From: ZhuangYumin Date: Mon, 6 Nov 2023 11:47:56 +0800 Subject: [PATCH] upd: add some files --- .vscode/launch.json | 16 + CMakeLists.txt | 10 +- {src => include}/Evalvisitor.h | 0 libs/CMakeLists.txt | 1 + libs/clipp/clipp.h | 7024 +++++ libs/int2048/CMakeLists.txt | 4 + libs/int2048/int2048.cpp | 931 + libs/int2048/int2048.h | 139 + libs/json/json.hpp | 24596 ++++++++++++++++ src/Evalvisitor.cpp | 1 + src/main.cpp | 1 + test/CMakeLists.txt | 9 + test/config.json | 7 + test/test-core.cpp | 122 + .../testcases}/basic-testcases/test0.in | 0 .../testcases}/basic-testcases/test0.out | 0 .../testcases}/basic-testcases/test1.in | 0 .../testcases}/basic-testcases/test1.out | 0 .../testcases}/basic-testcases/test10.in | 0 .../testcases}/basic-testcases/test10.out | 0 .../testcases}/basic-testcases/test11.in | 0 .../testcases}/basic-testcases/test11.out | 0 .../testcases}/basic-testcases/test12.in | 0 .../testcases}/basic-testcases/test12.out | 0 .../testcases}/basic-testcases/test13.in | 0 .../testcases}/basic-testcases/test13.out | 0 .../testcases}/basic-testcases/test2.in | 0 .../testcases}/basic-testcases/test2.out | 0 .../testcases}/basic-testcases/test3.in | 0 .../testcases}/basic-testcases/test3.out | 0 .../testcases}/basic-testcases/test4.in | 0 .../testcases}/basic-testcases/test4.out | 0 .../testcases}/basic-testcases/test5.in | 0 .../testcases}/basic-testcases/test5.out | 0 .../testcases}/basic-testcases/test6.in | 0 .../testcases}/basic-testcases/test6.out | 0 .../testcases}/basic-testcases/test7.in | 0 .../testcases}/basic-testcases/test7.out | 0 .../testcases}/basic-testcases/test8.in | 0 .../testcases}/basic-testcases/test8.out | 0 .../testcases}/basic-testcases/test9.in | 0 .../testcases}/basic-testcases/test9.out | 0 .../bigint-testcases/BigIntegerTest0.in | 0 .../bigint-testcases/BigIntegerTest0.out | 0 .../bigint-testcases/BigIntegerTest1.in | 0 .../bigint-testcases/BigIntegerTest1.out | 0 .../bigint-testcases/BigIntegerTest10.in | 0 .../bigint-testcases/BigIntegerTest10.out | 0 .../bigint-testcases/BigIntegerTest11.in | 0 .../bigint-testcases/BigIntegerTest11.out | 0 .../bigint-testcases/BigIntegerTest12.in | 0 .../bigint-testcases/BigIntegerTest12.out | 0 .../bigint-testcases/BigIntegerTest13.in | 0 .../bigint-testcases/BigIntegerTest13.out | 0 .../bigint-testcases/BigIntegerTest14.in | 0 .../bigint-testcases/BigIntegerTest14.out | 0 .../bigint-testcases/BigIntegerTest15.in | 0 .../bigint-testcases/BigIntegerTest15.out | 0 .../bigint-testcases/BigIntegerTest16.in | 0 .../bigint-testcases/BigIntegerTest16.out | 0 .../bigint-testcases/BigIntegerTest17.in | 0 .../bigint-testcases/BigIntegerTest17.out | 0 .../bigint-testcases/BigIntegerTest18.in | 0 .../bigint-testcases/BigIntegerTest18.out | 0 .../bigint-testcases/BigIntegerTest19.in | 0 .../bigint-testcases/BigIntegerTest19.out | 0 .../bigint-testcases/BigIntegerTest2.in | 0 .../bigint-testcases/BigIntegerTest2.out | 0 .../bigint-testcases/BigIntegerTest3.in | 0 .../bigint-testcases/BigIntegerTest3.out | 0 .../bigint-testcases/BigIntegerTest4.in | 0 .../bigint-testcases/BigIntegerTest4.out | 0 .../bigint-testcases/BigIntegerTest5.in | 0 .../bigint-testcases/BigIntegerTest5.out | 0 .../bigint-testcases/BigIntegerTest6.in | 0 .../bigint-testcases/BigIntegerTest6.out | 0 .../bigint-testcases/BigIntegerTest7.in | 0 .../bigint-testcases/BigIntegerTest7.out | 0 .../bigint-testcases/BigIntegerTest8.in | 0 .../bigint-testcases/BigIntegerTest8.out | 0 .../bigint-testcases/BigIntegerTest9.in | 0 .../bigint-testcases/BigIntegerTest9.out | 0 {testcases => test/testcases}/test.py | 0 83 files changed, 32860 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json rename {src => include}/Evalvisitor.h (100%) create mode 100644 libs/CMakeLists.txt create mode 100644 libs/clipp/clipp.h create mode 100644 libs/int2048/CMakeLists.txt create mode 100644 libs/int2048/int2048.cpp create mode 100644 libs/int2048/int2048.h create mode 100644 libs/json/json.hpp create mode 100644 test/CMakeLists.txt create mode 100644 test/config.json create mode 100644 test/test-core.cpp rename {testcases => test/testcases}/basic-testcases/test0.in (100%) rename {testcases => test/testcases}/basic-testcases/test0.out (100%) rename {testcases => test/testcases}/basic-testcases/test1.in (100%) rename {testcases => test/testcases}/basic-testcases/test1.out (100%) rename {testcases => test/testcases}/basic-testcases/test10.in (100%) rename {testcases => test/testcases}/basic-testcases/test10.out (100%) rename {testcases => test/testcases}/basic-testcases/test11.in (100%) rename {testcases => test/testcases}/basic-testcases/test11.out (100%) rename {testcases => test/testcases}/basic-testcases/test12.in (100%) rename {testcases => test/testcases}/basic-testcases/test12.out (100%) rename {testcases => test/testcases}/basic-testcases/test13.in (100%) rename {testcases => test/testcases}/basic-testcases/test13.out (100%) rename {testcases => test/testcases}/basic-testcases/test2.in (100%) rename {testcases => test/testcases}/basic-testcases/test2.out (100%) rename {testcases => test/testcases}/basic-testcases/test3.in (100%) rename {testcases => test/testcases}/basic-testcases/test3.out (100%) rename {testcases => test/testcases}/basic-testcases/test4.in (100%) rename {testcases => test/testcases}/basic-testcases/test4.out (100%) rename {testcases => test/testcases}/basic-testcases/test5.in (100%) rename {testcases => test/testcases}/basic-testcases/test5.out (100%) rename {testcases => test/testcases}/basic-testcases/test6.in (100%) rename {testcases => test/testcases}/basic-testcases/test6.out (100%) rename {testcases => test/testcases}/basic-testcases/test7.in (100%) rename {testcases => test/testcases}/basic-testcases/test7.out (100%) rename {testcases => test/testcases}/basic-testcases/test8.in (100%) rename {testcases => test/testcases}/basic-testcases/test8.out (100%) rename {testcases => test/testcases}/basic-testcases/test9.in (100%) rename {testcases => test/testcases}/basic-testcases/test9.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest0.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest0.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest1.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest1.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest10.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest10.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest11.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest11.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest12.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest12.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest13.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest13.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest14.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest14.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest15.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest15.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest16.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest16.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest17.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest17.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest18.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest18.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest19.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest19.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest2.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest2.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest3.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest3.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest4.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest4.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest5.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest5.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest6.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest6.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest7.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest7.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest8.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest8.out (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest9.in (100%) rename {testcases => test/testcases}/bigint-testcases/BigIntegerTest9.out (100%) rename {testcases => test/testcases}/test.py (100%) diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..39470fb --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "2.3.1", + "configurations": [ + + { + "name": "Debug ANTLR4 grammar", + "type": "antlr-debug", + "request": "launch", + "input": "./a.txt", // 输入文件(即你要运行的 Python 代码文件) + "grammar": "./resources/Python3Parser.g4", // 语法文件 + "startRule": "file_input", // 语法入口规则,我们的公式语法入口规则是 file_input + "printParseTree": true, // 是否 打印/可视化 parse tree + "visualParseTree": true + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f77cfed..2ba3478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,11 +13,19 @@ include_directories( add_subdirectory(${PROJECT_SOURCE_DIR}/generated) ### YOU CAN"T MODIFY THE CODE ABOVE +add_subdirectory(libs) +add_subdirectory(test) file(GLOB_RECURSE main_src src/*.cpp) +include_directories(${PROJECT_SOURCE_DIR}/include) +link_directories(${PROJECT_SOURCE_DIR}/src) + add_executable(code ${main_src}) # Add all *.cpp file after src/main.cpp, like src/Evalvisitor.cpp did +target_include_directories(code PRIVATE ${PROJECT_SOURCE_DIR}/libs) +target_link_directories(code PRIVATE ${PROJECT_SOURCE_DIR}/libs/int2048) +target_link_libraries(code int2048) ### YOU CAN'T MODIFY THE CODE BELOW target_link_libraries(code PyAntlr) target_link_libraries(code antlr4-runtime) -### YOU CAN"T MODIFY THE CODE ABOVE +### YOU CAN"T MODIFY THE CODE ABOVE \ No newline at end of file diff --git a/src/Evalvisitor.h b/include/Evalvisitor.h similarity index 100% rename from src/Evalvisitor.h rename to include/Evalvisitor.h diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt new file mode 100644 index 0000000..df4173c --- /dev/null +++ b/libs/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(int2048) \ No newline at end of file diff --git a/libs/clipp/clipp.h b/libs/clipp/clipp.h new file mode 100644 index 0000000..d7b101e --- /dev/null +++ b/libs/clipp/clipp.h @@ -0,0 +1,7024 @@ +/***************************************************************************** + * ___ _ _ ___ ___ + * | _|| | | | | _ \ _ \ CLIPP - command line interfaces for modern C++ + * | |_ | |_ | | | _/ _/ version 1.2.3 + * |___||___||_| |_| |_| https://github.com/muellan/clipp + * + * Licensed under the MIT License . + * Copyright (c) 2017-2018 André Müller + * + * --------------------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ + +#ifndef AM_CLIPP_H__ +#define AM_CLIPP_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/*************************************************************************//** + * + * @brief primary namespace + * + *****************************************************************************/ +namespace clipp { + + + +/***************************************************************************** + * + * basic constants and datatype definitions + * + *****************************************************************************/ +using arg_index = int; + +using arg_string = std::string; +using doc_string = std::string; + +using arg_list = std::vector; + + + +/*************************************************************************//** + * + * @brief tristate + * + *****************************************************************************/ +enum class tri : char { no, yes, either }; + +inline constexpr bool operator == (tri t, bool b) noexcept { + return b ? t != tri::no : t != tri::yes; +} +inline constexpr bool operator == (bool b, tri t) noexcept { return (t == b); } +inline constexpr bool operator != (tri t, bool b) noexcept { return !(t == b); } +inline constexpr bool operator != (bool b, tri t) noexcept { return !(t == b); } + + + +/*************************************************************************//** + * + * @brief (start,size) index range + * + *****************************************************************************/ +class subrange { +public: + using size_type = arg_string::size_type; + + /** @brief default: no match */ + explicit constexpr + subrange() noexcept : + at_{arg_string::npos}, length_{0} + {} + + /** @brief match length & position within subject string */ + explicit constexpr + subrange(size_type pos, size_type len) noexcept : + at_{pos}, length_{len} + {} + + /** @brief position of the match within the subject string */ + constexpr size_type at() const noexcept { return at_; } + /** @brief length of the matching subsequence */ + constexpr size_type length() const noexcept { return length_; } + + /** @brief returns true, if query string is a prefix of the subject string */ + constexpr bool prefix() const noexcept { + return at_ == 0; + } + + /** @brief returns true, if query is a substring of the query string */ + constexpr explicit operator bool () const noexcept { + return at_ != arg_string::npos; + } + +private: + size_type at_; + size_type length_; +}; + + + +/*************************************************************************//** + * + * @brief match predicates + * + *****************************************************************************/ +using match_predicate = std::function; +using match_function = std::function; + + + + + + +/*************************************************************************//** + * + * @brief type traits (NOT FOR DIRECT USE IN CLIENT CODE!) + * no interface guarantees; might be changed or removed in the future + * + *****************************************************************************/ +namespace traits { + +/*************************************************************************//** + * + * @brief function (class) signature type trait + * + *****************************************************************************/ +template +constexpr auto +check_is_callable(int) -> decltype( + std::declval()(std::declval()...), + std::integral_constant::type>::value>{} ); + +template +constexpr auto +check_is_callable(long) -> std::false_type; + +template +constexpr auto +check_is_callable_without_arg(int) -> decltype( + std::declval()(), + std::integral_constant::type>::value>{} ); + +template +constexpr auto +check_is_callable_without_arg(long) -> std::false_type; + + + +template +constexpr auto +check_is_void_callable(int) -> decltype( + std::declval()(std::declval()...), std::true_type{}); + +template +constexpr auto +check_is_void_callable(long) -> std::false_type; + +template +constexpr auto +check_is_void_callable_without_arg(int) -> decltype( + std::declval()(), std::true_type{}); + +template +constexpr auto +check_is_void_callable_without_arg(long) -> std::false_type; + + + +template +struct is_callable; + + +template +struct is_callable : + decltype(check_is_callable(0)) +{}; + +template +struct is_callable : + decltype(check_is_callable_without_arg(0)) +{}; + + +template +struct is_callable : + decltype(check_is_void_callable(0)) +{}; + +template +struct is_callable : + decltype(check_is_void_callable_without_arg(0)) +{}; + + + +/*************************************************************************//** + * + * @brief input range type trait + * + *****************************************************************************/ +template +constexpr auto +check_is_input_range(int) -> decltype( + begin(std::declval()), end(std::declval()), + std::true_type{}); + +template +constexpr auto +check_is_input_range(char) -> decltype( + std::begin(std::declval()), std::end(std::declval()), + std::true_type{}); + +template +constexpr auto +check_is_input_range(long) -> std::false_type; + +template +struct is_input_range : + decltype(check_is_input_range(0)) +{}; + + + +/*************************************************************************//** + * + * @brief size() member type trait + * + *****************************************************************************/ +template +constexpr auto +check_has_size_getter(int) -> + decltype(std::declval().size(), std::true_type{}); + +template +constexpr auto +check_has_size_getter(long) -> std::false_type; + +template +struct has_size_getter : + decltype(check_has_size_getter(0)) +{}; + +} // namespace traits + + + + + + +/*************************************************************************//** + * + * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!) + * no interface guarantees; might be changed or removed in the future + * + *****************************************************************************/ +namespace detail { + + +/*************************************************************************//** + * @brief forwards string to first non-whitespace char; + * std string -> unsigned conv yields max value, but we want 0; + * also checks for nullptr + *****************************************************************************/ +inline bool +fwd_to_unsigned_int(const char*& s) +{ + if(!s) return false; + for(; std::isspace(*s); ++s); + if(!s[0] || s[0] == '-') return false; + if(s[0] == '-') return false; + return true; +} + + +/*************************************************************************//** + * + * @brief value limits clamping + * + *****************************************************************************/ +template sizeof(T))> +struct limits_clamped { + static T from(const V& v) { + if(v >= V(std::numeric_limits::max())) { + return std::numeric_limits::max(); + } + if(v <= V(std::numeric_limits::lowest())) { + return std::numeric_limits::lowest(); + } + return T(v); + } +}; + +template +struct limits_clamped { + static T from(const V& v) { return T(v); } +}; + + +/*************************************************************************//** + * + * @brief returns value of v as a T, clamped at T's maximum + * + *****************************************************************************/ +template +inline T clamped_on_limits(const V& v) { + return limits_clamped::from(v); +} + + + + +/*************************************************************************//** + * + * @brief type conversion helpers + * + *****************************************************************************/ +template +struct make { + static inline T from(const char* s) { + if(!s) return false; + //a conversion from const char* to / must exist + return static_cast(s); + } +}; + +template<> +struct make { + static inline bool from(const char* s) { + if(!s) return false; + return static_cast(s); + } +}; + +template<> +struct make { + static inline unsigned char from(const char* s) { + if(!fwd_to_unsigned_int(s)) return (0); + return clamped_on_limits(std::strtoull(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline unsigned short int from(const char* s) { + if(!fwd_to_unsigned_int(s)) return (0); + return clamped_on_limits(std::strtoull(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline unsigned int from(const char* s) { + if(!fwd_to_unsigned_int(s)) return (0); + return clamped_on_limits(std::strtoull(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline unsigned long int from(const char* s) { + if(!fwd_to_unsigned_int(s)) return (0); + return clamped_on_limits(std::strtoull(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline unsigned long long int from(const char* s) { + if(!fwd_to_unsigned_int(s)) return (0); + return clamped_on_limits(std::strtoull(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline char from(const char* s) { + //parse as single character? + const auto n = std::strlen(s); + if(n == 1) return s[0]; + //parse as integer + return clamped_on_limits(std::strtoll(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline short int from(const char* s) { + return clamped_on_limits(std::strtoll(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline int from(const char* s) { + return clamped_on_limits(std::strtoll(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline long int from(const char* s) { + return clamped_on_limits(std::strtoll(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline long long int from(const char* s) { + return (std::strtoll(s,nullptr,10)); + } +}; + +template<> +struct make { + static inline float from(const char* s) { + return (std::strtof(s,nullptr)); + } +}; + +template<> +struct make { + static inline double from(const char* s) { + return (std::strtod(s,nullptr)); + } +}; + +template<> +struct make { + static inline long double from(const char* s) { + return (std::strtold(s,nullptr)); + } +}; + +template<> +struct make { + static inline std::string from(const char* s) { + return std::string(s); + } +}; + + + +/*************************************************************************//** + * + * @brief assigns boolean constant to one or multiple target objects + * + *****************************************************************************/ +template +class assign_value +{ +public: + template + explicit constexpr + assign_value(T& target, X&& value) noexcept : + t_{std::addressof(target)}, v_{std::forward(value)} + {} + + void operator () () const { + if(t_) *t_ = v_; + } + +private: + T* t_; + V v_; +}; + + + +/*************************************************************************//** + * + * @brief flips bools + * + *****************************************************************************/ +class flip_bool +{ +public: + explicit constexpr + flip_bool(bool& target) noexcept : + b_{&target} + {} + + void operator () () const { + if(b_) *b_ = !*b_; + } + +private: + bool* b_; +}; + + + +/*************************************************************************//** + * + * @brief increments using operator ++ + * + *****************************************************************************/ +template +class increment +{ +public: + explicit constexpr + increment(T& target) noexcept : t_{std::addressof(target)} {} + + void operator () () const { + if(t_) ++(*t_); + } + +private: + T* t_; +}; + + + +/*************************************************************************//** + * + * @brief decrements using operator -- + * + *****************************************************************************/ +template +class decrement +{ +public: + explicit constexpr + decrement(T& target) noexcept : t_{std::addressof(target)} {} + + void operator () () const { + if(t_) --(*t_); + } + +private: + T* t_; +}; + + + +/*************************************************************************//** + * + * @brief increments by a fixed amount using operator += + * + *****************************************************************************/ +template +class increment_by +{ +public: + explicit constexpr + increment_by(T& target, T by) noexcept : + t_{std::addressof(target)}, by_{std::move(by)} + {} + + void operator () () const { + if(t_) (*t_) += by_; + } + +private: + T* t_; + T by_; +}; + + + + +/*************************************************************************//** + * + * @brief makes a value from a string and assigns it to an object + * + *****************************************************************************/ +template +class map_arg_to +{ +public: + explicit constexpr + map_arg_to(T& target) noexcept : t_{std::addressof(target)} {} + + void operator () (const char* s) const { + if(t_ && s) *t_ = detail::make::from(s); + } + +private: + T* t_; +}; + + +//------------------------------------------------------------------- +/** + * @brief specialization for vectors: append element + */ +template +class map_arg_to> +{ +public: + map_arg_to(std::vector& target): t_{std::addressof(target)} {} + + void operator () (const char* s) const { + if(t_ && s) t_->push_back(detail::make::from(s)); + } + +private: + std::vector* t_; +}; + + +//------------------------------------------------------------------- +/** + * @brief specialization for bools: + * set to true regardless of string content + */ +template<> +class map_arg_to +{ +public: + map_arg_to(bool& target): t_{&target} {} + + void operator () (const char* s) const { + if(t_ && s) *t_ = true; + } + +private: + bool* t_; +}; + + +} // namespace detail + + + + + + +/*************************************************************************//** + * + * @brief string matching and processing tools + * + *****************************************************************************/ + +namespace str { + + +/*************************************************************************//** + * + * @brief converts string to value of target type 'T' + * + *****************************************************************************/ +template +T make(const arg_string& s) +{ + return detail::make::from(s); +} + + + +/*************************************************************************//** + * + * @brief removes trailing whitespace from string + * + *****************************************************************************/ +template +inline void +trimr(std::basic_string& s) +{ + if(s.empty()) return; + + s.erase( + std::find_if_not(s.rbegin(), s.rend(), + [](char c) { return std::isspace(c);} ).base(), + s.end() ); +} + + +/*************************************************************************//** + * + * @brief removes leading whitespace from string + * + *****************************************************************************/ +template +inline void +triml(std::basic_string& s) +{ + if(s.empty()) return; + + s.erase( + s.begin(), + std::find_if_not(s.begin(), s.end(), + [](char c) { return std::isspace(c);}) + ); +} + + +/*************************************************************************//** + * + * @brief removes leading and trailing whitespace from string + * + *****************************************************************************/ +template +inline void +trim(std::basic_string& s) +{ + triml(s); + trimr(s); +} + + +/*************************************************************************//** + * + * @brief removes all whitespaces from string + * + *****************************************************************************/ +template +inline void +remove_ws(std::basic_string& s) +{ + if(s.empty()) return; + + s.erase(std::remove_if(s.begin(), s.end(), + [](char c) { return std::isspace(c); }), + s.end() ); +} + + +/*************************************************************************//** + * + * @brief returns true, if the 'prefix' argument + * is a prefix of the 'subject' argument + * + *****************************************************************************/ +template +inline bool +has_prefix(const std::basic_string& subject, + const std::basic_string& prefix) +{ + if(prefix.size() > subject.size()) return false; + return subject.find(prefix) == 0; +} + + +/*************************************************************************//** + * + * @brief returns true, if the 'postfix' argument + * is a postfix of the 'subject' argument + * + *****************************************************************************/ +template +inline bool +has_postfix(const std::basic_string& subject, + const std::basic_string& postfix) +{ + if(postfix.size() > subject.size()) return false; + return (subject.size() - postfix.size()) == subject.find(postfix); +} + + + +/*************************************************************************//** +* +* @brief returns longest common prefix of several +* sequential random access containers +* +* @details InputRange require begin and end (member functions or overloads) +* the elements of InputRange require a size() member +* +*****************************************************************************/ +template +auto +longest_common_prefix(const InputRange& strs) + -> typename std::decay::type +{ + static_assert(traits::is_input_range(), + "parameter must satisfy the InputRange concept"); + + static_assert(traits::has_size_getter< + typename std::decay::type>(), + "elements of input range must have a ::size() member function"); + + using std::begin; + using std::end; + + using item_t = typename std::decay::type; + using str_size_t = typename std::decaysize())>::type; + + const auto n = size_t(distance(begin(strs), end(strs))); + if(n < 1) return item_t(""); + if(n == 1) return *begin(strs); + + //length of shortest string + auto m = std::min_element(begin(strs), end(strs), + [](const item_t& a, const item_t& b) { + return a.size() < b.size(); })->size(); + + //check each character until we find a mismatch + for(str_size_t i = 0; i < m; ++i) { + for(str_size_t j = 1; j < n; ++j) { + if(strs[j][i] != strs[j-1][i]) + return strs[0].substr(0, i); + } + } + return strs[0].substr(0, m); +} + + + +/*************************************************************************//** + * + * @brief returns longest substring range that could be found in 'arg' + * + * @param arg string to be searched in + * @param substrings range of candidate substrings + * + *****************************************************************************/ +template +subrange +longest_substring_match(const std::basic_string& arg, + const InputRange& substrings) +{ + using string_t = std::basic_string; + + static_assert(traits::is_input_range(), + "parameter must satisfy the InputRange concept"); + + static_assert(std::is_same::type>(), + "substrings must have same type as 'arg'"); + + auto i = string_t::npos; + auto n = string_t::size_type(0); + for(const auto& s : substrings) { + auto j = arg.find(s); + if(j != string_t::npos && s.size() > n) { + i = j; + n = s.size(); + } + } + return subrange{i,n}; +} + + + +/*************************************************************************//** + * + * @brief returns longest prefix range that could be found in 'arg' + * + * @param arg string to be searched in + * @param prefixes range of candidate prefix strings + * + *****************************************************************************/ +template +subrange +longest_prefix_match(const std::basic_string& arg, + const InputRange& prefixes) +{ + using string_t = std::basic_string; + using s_size_t = typename string_t::size_type; + + static_assert(traits::is_input_range(), + "parameter must satisfy the InputRange concept"); + + static_assert(std::is_same::type>(), + "prefixes must have same type as 'arg'"); + + auto i = string_t::npos; + auto n = s_size_t(0); + for(const auto& s : prefixes) { + auto j = arg.find(s); + if(j == 0 && s.size() > n) { + i = 0; + n = s.size(); + } + } + return subrange{i,n}; +} + + + +/*************************************************************************//** + * + * @brief returns the first occurrence of 'query' within 'subject' + * + *****************************************************************************/ +template +inline subrange +substring_match(const std::basic_string& subject, + const std::basic_string& query) +{ + if(subject.empty() && query.empty()) return subrange(0,0); + if(subject.empty() || query.empty()) return subrange{}; + auto i = subject.find(query); + if(i == std::basic_string::npos) return subrange{}; + return subrange{i,query.size()}; +} + + + +/*************************************************************************//** + * + * @brief returns first substring match (pos,len) within the input string + * that represents a number + * (with at maximum one decimal point and digit separators) + * + *****************************************************************************/ +template +subrange +first_number_match(std::basic_string s, + C digitSeparator = C(','), + C decimalPoint = C('.'), + C exponential = C('e')) +{ + using string_t = std::basic_string; + + str::trim(s); + if(s.empty()) return subrange{}; + + auto i = s.find_first_of("0123456789+-"); + if(i == string_t::npos) { + i = s.find(decimalPoint); + if(i == string_t::npos) return subrange{}; + } + + bool point = false; + bool sep = false; + auto exp = string_t::npos; + auto j = i + 1; + for(; j < s.size(); ++j) { + if(s[j] == digitSeparator) { + if(!sep) sep = true; else break; + } + else { + sep = false; + if(s[j] == decimalPoint) { + //only one decimal point before exponent allowed + if(!point && exp == string_t::npos) point = true; else break; + } + else if(std::tolower(s[j]) == std::tolower(exponential)) { + //only one exponent separator allowed + if(exp == string_t::npos) exp = j; else break; + } + else if(exp != string_t::npos && (exp+1) == j) { + //only sign or digit after exponent separator + if(s[j] != '+' && s[j] != '-' && !std::isdigit(s[j])) break; + } + else if(!std::isdigit(s[j])) { + break; + } + } + } + + //if length == 1 then must be a digit + if(j-i == 1 && !std::isdigit(s[i])) return subrange{}; + + return subrange{i,j-i}; +} + + + +/*************************************************************************//** + * + * @brief returns first substring match (pos,len) + * that represents an integer (with optional digit separators) + * + *****************************************************************************/ +template +subrange +first_integer_match(std::basic_string s, + C digitSeparator = C(',')) +{ + using string_t = std::basic_string; + + str::trim(s); + if(s.empty()) return subrange{}; + + auto i = s.find_first_of("0123456789+-"); + if(i == string_t::npos) return subrange{}; + + bool sep = false; + auto j = i + 1; + for(; j < s.size(); ++j) { + if(s[j] == digitSeparator) { + if(!sep) sep = true; else break; + } + else { + sep = false; + if(!std::isdigit(s[j])) break; + } + } + + //if length == 1 then must be a digit + if(j-i == 1 && !std::isdigit(s[i])) return subrange{}; + + return subrange{i,j-i}; +} + + + +/*************************************************************************//** + * + * @brief returns true if candidate string represents a number + * + *****************************************************************************/ +template +bool represents_number(const std::basic_string& candidate, + C digitSeparator = C(','), + C decimalPoint = C('.'), + C exponential = C('e')) +{ + const auto match = str::first_number_match(candidate, digitSeparator, + decimalPoint, exponential); + + return (match && match.length() == candidate.size()); +} + + + +/*************************************************************************//** + * + * @brief returns true if candidate string represents an integer + * + *****************************************************************************/ +template +bool represents_integer(const std::basic_string& candidate, + C digitSeparator = C(',')) +{ + const auto match = str::first_integer_match(candidate, digitSeparator); + return (match && match.length() == candidate.size()); +} + +} // namespace str + + + + + + +/*************************************************************************//** + * + * @brief makes function object with a const char* parameter + * that assigns a value to a ref-captured object + * + *****************************************************************************/ +template +inline detail::assign_value +set(T& target, V value) { + return detail::assign_value{target, std::move(value)}; +} + + + +/*************************************************************************//** + * + * @brief makes parameter-less function object + * that assigns value(s) to a ref-captured object; + * value(s) are obtained by converting the const char* argument to + * the captured object types; + * bools are always set to true if the argument is not nullptr + * + *****************************************************************************/ +template +inline detail::map_arg_to +set(T& target) { + return detail::map_arg_to{target}; +} + + + +/*************************************************************************//** + * + * @brief makes function object that sets a bool to true + * + *****************************************************************************/ +inline detail::assign_value +set(bool& target) { + return detail::assign_value{target,true}; +} + +/*************************************************************************//** + * + * @brief makes function object that sets a bool to false + * + *****************************************************************************/ +inline detail::assign_value +unset(bool& target) { + return detail::assign_value{target,false}; +} + +/*************************************************************************//** + * + * @brief makes function object that flips the value of a ref-captured bool + * + *****************************************************************************/ +inline detail::flip_bool +flip(bool& b) { + return detail::flip_bool(b); +} + + + + + +/*************************************************************************//** + * + * @brief makes function object that increments using operator ++ + * + *****************************************************************************/ +template +inline detail::increment +increment(T& target) { + return detail::increment{target}; +} + +/*************************************************************************//** + * + * @brief makes function object that decrements using operator -- + * + *****************************************************************************/ +template +inline detail::increment_by +increment(T& target, T by) { + return detail::increment_by{target, std::move(by)}; +} + +/*************************************************************************//** + * + * @brief makes function object that increments by a fixed amount using operator += + * + *****************************************************************************/ +template +inline detail::decrement +decrement(T& target) { + return detail::decrement{target}; +} + + + + + + +/*************************************************************************//** + * + * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!) + * + *****************************************************************************/ +namespace detail { + + +/*************************************************************************//** + * + * @brief mixin that provides action definition and execution + * + *****************************************************************************/ +template +class action_provider +{ +private: + //--------------------------------------------------------------- + using simple_action = std::function; + using arg_action = std::function; + using index_action = std::function; + + //----------------------------------------------------- + class simple_action_adapter { + public: + simple_action_adapter() = default; + simple_action_adapter(const simple_action& a): action_(a) {} + simple_action_adapter(simple_action&& a): action_(std::move(a)) {} + void operator() (const char*) const { action_(); } + void operator() (int) const { action_(); } + private: + simple_action action_; + }; + + +public: + //--------------------------------------------------------------- + /** @brief adds an action that has an operator() that is callable + * with a 'const char*' argument */ + Derived& + call(arg_action a) { + argActions_.push_back(std::move(a)); + return *static_cast(this); + } + + /** @brief adds an action that has an operator()() */ + Derived& + call(simple_action a) { + argActions_.push_back(simple_action_adapter(std::move(a))); + return *static_cast(this); + } + + /** @brief adds an action that has an operator() that is callable + * with a 'const char*' argument */ + Derived& operator () (arg_action a) { return call(std::move(a)); } + + /** @brief adds an action that has an operator()() */ + Derived& operator () (simple_action a) { return call(std::move(a)); } + + + //--------------------------------------------------------------- + /** @brief adds an action that will set the value of 't' from + * a 'const char*' arg */ + template + Derived& + set(Target& t) { + static_assert(!std::is_pointer::value, + "parameter target type must not be a pointer"); + + return call(clipp::set(t)); + } + + /** @brief adds an action that will set the value of 't' to 'v' */ + template + Derived& + set(Target& t, Value&& v) { + return call(clipp::set(t, std::forward(v))); + } + + + //--------------------------------------------------------------- + /** @brief adds an action that will be called if a parameter + * matches an argument for the 2nd, 3rd, 4th, ... time + */ + Derived& + if_repeated(simple_action a) { + repeatActions_.push_back(simple_action_adapter{std::move(a)}); + return *static_cast(this); + } + /** @brief adds an action that will be called with the argument's + * index if a parameter matches an argument for + * the 2nd, 3rd, 4th, ... time + */ + Derived& + if_repeated(index_action a) { + repeatActions_.push_back(std::move(a)); + return *static_cast(this); + } + + + //--------------------------------------------------------------- + /** @brief adds an action that will be called if a required parameter + * is missing + */ + Derived& + if_missing(simple_action a) { + missingActions_.push_back(simple_action_adapter{std::move(a)}); + return *static_cast(this); + } + /** @brief adds an action that will be called if a required parameter + * is missing; the action will get called with the index of + * the command line argument where the missing event occurred first + */ + Derived& + if_missing(index_action a) { + missingActions_.push_back(std::move(a)); + return *static_cast(this); + } + + + //--------------------------------------------------------------- + /** @brief adds an action that will be called if a parameter + * was matched, but was unreachable in the current scope + */ + Derived& + if_blocked(simple_action a) { + blockedActions_.push_back(simple_action_adapter{std::move(a)}); + return *static_cast(this); + } + /** @brief adds an action that will be called if a parameter + * was matched, but was unreachable in the current scope; + * the action will be called with the index of + * the command line argument where the problem occurred + */ + Derived& + if_blocked(index_action a) { + blockedActions_.push_back(std::move(a)); + return *static_cast(this); + } + + + //--------------------------------------------------------------- + /** @brief adds an action that will be called if a parameter match + * was in conflict with a different alternative parameter + */ + Derived& + if_conflicted(simple_action a) { + conflictActions_.push_back(simple_action_adapter{std::move(a)}); + return *static_cast(this); + } + /** @brief adds an action that will be called if a parameter match + * was in conflict with a different alternative parameter; + * the action will be called with the index of + * the command line argument where the problem occurred + */ + Derived& + if_conflicted(index_action a) { + conflictActions_.push_back(std::move(a)); + return *static_cast(this); + } + + + //--------------------------------------------------------------- + /** @brief adds targets = either objects whose values should be + * set by command line arguments or actions that should + * be called in case of a match */ + template + Derived& + target(T&& t, Ts&&... ts) { + target(std::forward(t)); + target(std::forward(ts)...); + return *static_cast(this); + } + + /** @brief adds action that should be called in case of a match */ + template::type>() && + (traits::is_callable() || + traits::is_callable() ) + >::type> + Derived& + target(T&& t) { + call(std::forward(t)); + return *static_cast(this); + } + + /** @brief adds object whose value should be set by command line arguments + */ + template::type>() || + (!traits::is_callable() && + !traits::is_callable() ) + >::type> + Derived& + target(T& t) { + set(t); + return *static_cast(this); + } + + //TODO remove ugly empty param list overload + Derived& + target() { + return *static_cast(this); + } + + + //--------------------------------------------------------------- + /** @brief adds target, see member function 'target' */ + template + inline friend Derived& + operator << (Target&& t, Derived& p) { + p.target(std::forward(t)); + return p; + } + /** @brief adds target, see member function 'target' */ + template + inline friend Derived&& + operator << (Target&& t, Derived&& p) { + p.target(std::forward(t)); + return std::move(p); + } + + //----------------------------------------------------- + /** @brief adds target, see member function 'target' */ + template + inline friend Derived& + operator >> (Derived& p, Target&& t) { + p.target(std::forward(t)); + return p; + } + /** @brief adds target, see member function 'target' */ + template + inline friend Derived&& + operator >> (Derived&& p, Target&& t) { + p.target(std::forward(t)); + return std::move(p); + } + + + //--------------------------------------------------------------- + /** @brief executes all argument actions */ + void execute_actions(const arg_string& arg) const { + int i = 0; + for(const auto& a : argActions_) { + ++i; + a(arg.c_str()); + } + } + + /** @brief executes repeat actions */ + void notify_repeated(arg_index idx) const { + for(const auto& a : repeatActions_) a(idx); + } + /** @brief executes missing error actions */ + void notify_missing(arg_index idx) const { + for(const auto& a : missingActions_) a(idx); + } + /** @brief executes blocked error actions */ + void notify_blocked(arg_index idx) const { + for(const auto& a : blockedActions_) a(idx); + } + /** @brief executes conflict error actions */ + void notify_conflict(arg_index idx) const { + for(const auto& a : conflictActions_) a(idx); + } + +private: + //--------------------------------------------------------------- + std::vector argActions_; + std::vector repeatActions_; + std::vector missingActions_; + std::vector blockedActions_; + std::vector conflictActions_; +}; + + + + + + +/*************************************************************************//** + * + * @brief mixin that provides basic common settings of parameters and groups + * + *****************************************************************************/ +template +class token +{ +public: + //--------------------------------------------------------------- + using doc_string = clipp::doc_string; + + + //--------------------------------------------------------------- + /** @brief returns documentation string */ + const doc_string& doc() const noexcept { + return doc_; + } + + /** @brief sets documentations string */ + Derived& doc(const doc_string& txt) { + doc_ = txt; + return *static_cast(this); + } + + /** @brief sets documentations string */ + Derived& doc(doc_string&& txt) { + doc_ = std::move(txt); + return *static_cast(this); + } + + + //--------------------------------------------------------------- + /** @brief returns if a group/parameter is repeatable */ + bool repeatable() const noexcept { + return repeatable_; + } + + /** @brief sets repeatability of group/parameter */ + Derived& repeatable(bool yes) noexcept { + repeatable_ = yes; + return *static_cast(this); + } + + + //--------------------------------------------------------------- + /** @brief returns if a group/parameter is blocking/positional */ + bool blocking() const noexcept { + return blocking_; + } + + /** @brief determines, if a group/parameter is blocking/positional */ + Derived& blocking(bool yes) noexcept { + blocking_ = yes; + return *static_cast(this); + } + + +private: + //--------------------------------------------------------------- + doc_string doc_; + bool repeatable_ = false; + bool blocking_ = false; +}; + + + + +/*************************************************************************//** + * + * @brief sets documentation strings on a token + * + *****************************************************************************/ +template +inline T& +operator % (doc_string docstr, token& p) +{ + return p.doc(std::move(docstr)); +} +//--------------------------------------------------------- +template +inline T&& +operator % (doc_string docstr, token&& p) +{ + return std::move(p.doc(std::move(docstr))); +} + +//--------------------------------------------------------- +template +inline T& +operator % (token& p, doc_string docstr) +{ + return p.doc(std::move(docstr)); +} +//--------------------------------------------------------- +template +inline T&& +operator % (token&& p, doc_string docstr) +{ + return std::move(p.doc(std::move(docstr))); +} + + + + +/*************************************************************************//** + * + * @brief sets documentation strings on a token + * + *****************************************************************************/ +template +inline T& +doc(doc_string docstr, token& p) +{ + return p.doc(std::move(docstr)); +} +//--------------------------------------------------------- +template +inline T&& +doc(doc_string docstr, token&& p) +{ + return std::move(p.doc(std::move(docstr))); +} + + + +} // namespace detail + + + +/*************************************************************************//** + * + * @brief contains parameter matching functions and function classes + * + *****************************************************************************/ +namespace match { + + +/*************************************************************************//** + * + * @brief predicate that is always true + * + *****************************************************************************/ +inline bool +any(const arg_string&) { return true; } + +/*************************************************************************//** + * + * @brief predicate that is always false + * + *****************************************************************************/ +inline bool +none(const arg_string&) { return false; } + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the argument string is non-empty string + * + *****************************************************************************/ +inline bool +nonempty(const arg_string& s) { + return !s.empty(); +} + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the argument is a non-empty + * string that consists only of alphanumeric characters + * + *****************************************************************************/ +inline bool +alphanumeric(const arg_string& s) { + if(s.empty()) return false; + return std::all_of(s.begin(), s.end(), [](char c) {return std::isalnum(c); }); +} + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the argument is a non-empty + * string that consists only of alphabetic characters + * + *****************************************************************************/ +inline bool +alphabetic(const arg_string& s) { + return std::all_of(s.begin(), s.end(), [](char c) {return std::isalpha(c); }); +} + + + +/*************************************************************************//** + * + * @brief predicate that returns false if the argument string is + * equal to any string from the exclusion list + * + *****************************************************************************/ +class none_of +{ +public: + none_of(arg_list strs): + excluded_{std::move(strs)} + {} + + template + none_of(arg_string str, Strings&&... strs): + excluded_{std::move(str), std::forward(strs)...} + {} + + template + none_of(const char* str, Strings&&... strs): + excluded_{arg_string(str), std::forward(strs)...} + {} + + bool operator () (const arg_string& arg) const { + return (std::find(begin(excluded_), end(excluded_), arg) + == end(excluded_)); + } + +private: + arg_list excluded_; +}; + + + +/*************************************************************************//** + * + * @brief predicate that returns the first substring match within the input + * string that rmeepresents a number + * (with at maximum one decimal point and digit separators) + * + *****************************************************************************/ +class numbers +{ +public: + explicit + numbers(char decimalPoint = '.', + char digitSeparator = ' ', + char exponentSeparator = 'e') + : + decpoint_{decimalPoint}, separator_{digitSeparator}, + exp_{exponentSeparator} + {} + + subrange operator () (const arg_string& s) const { + return str::first_number_match(s, separator_, decpoint_, exp_); + } + +private: + char decpoint_; + char separator_; + char exp_; +}; + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the input string represents an integer + * (with optional digit separators) + * + *****************************************************************************/ +class integers { +public: + explicit + integers(char digitSeparator = ' '): separator_{digitSeparator} {} + + subrange operator () (const arg_string& s) const { + return str::first_integer_match(s, separator_); + } + +private: + char separator_; +}; + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the input string represents + * a non-negative integer (with optional digit separators) + * + *****************************************************************************/ +class positive_integers { +public: + explicit + positive_integers(char digitSeparator = ' '): separator_{digitSeparator} {} + + subrange operator () (const arg_string& s) const { + auto match = str::first_integer_match(s, separator_); + if(!match) return subrange{}; + if(s[match.at()] == '-') return subrange{}; + return match; + } + +private: + char separator_; +}; + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the input string + * contains a given substring + * + *****************************************************************************/ +class substring +{ +public: + explicit + substring(arg_string str): str_{std::move(str)} {} + + subrange operator () (const arg_string& s) const { + return str::substring_match(s, str_); + } + +private: + arg_string str_; +}; + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the input string starts + * with a given prefix + * + *****************************************************************************/ +class prefix { +public: + explicit + prefix(arg_string p): prefix_{std::move(p)} {} + + bool operator () (const arg_string& s) const { + return s.find(prefix_) == 0; + } + +private: + arg_string prefix_; +}; + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the input string does not start + * with a given prefix + * + *****************************************************************************/ +class prefix_not { +public: + explicit + prefix_not(arg_string p): prefix_{std::move(p)} {} + + bool operator () (const arg_string& s) const { + return s.find(prefix_) != 0; + } + +private: + arg_string prefix_; +}; + + +/** @brief alias for prefix_not */ +using noprefix = prefix_not; + + + +/*************************************************************************//** + * + * @brief predicate that returns true if the length of the input string + * is wihtin a given interval + * + *****************************************************************************/ +class length { +public: + explicit + length(std::size_t exact): + min_{exact}, max_{exact} + {} + + explicit + length(std::size_t min, std::size_t max): + min_{min}, max_{max} + {} + + bool operator () (const arg_string& s) const { + return s.size() >= min_ && s.size() <= max_; + } + +private: + std::size_t min_; + std::size_t max_; +}; + + +/*************************************************************************//** + * + * @brief makes function object that returns true if the input string has a + * given minimum length + * + *****************************************************************************/ +inline length min_length(std::size_t min) +{ + return length{min, arg_string::npos-1}; +} + +/*************************************************************************//** + * + * @brief makes function object that returns true if the input string is + * not longer than a given maximum length + * + *****************************************************************************/ +inline length max_length(std::size_t max) +{ + return length{0, max}; +} + + +} // namespace match + + + + + +/*************************************************************************//** + * + * @brief command line parameter that can match one or many arguments. + * + *****************************************************************************/ +class parameter : + public detail::token, + public detail::action_provider +{ + /** @brief adapts a 'match_predicate' to the 'match_function' interface */ + class predicate_adapter { + public: + explicit + predicate_adapter(match_predicate pred): match_{std::move(pred)} {} + + subrange operator () (const arg_string& arg) const { + return match_(arg) ? subrange{0,arg.size()} : subrange{}; + } + + private: + match_predicate match_; + }; + +public: + //--------------------------------------------------------------- + /** @brief makes default parameter, that will match nothing */ + parameter(): + flags_{}, + matcher_{predicate_adapter{match::none}}, + label_{}, required_{false}, greedy_{false} + {} + + /** @brief makes "flag" parameter */ + template + explicit + parameter(arg_string str, Strings&&... strs): + flags_{}, + matcher_{predicate_adapter{match::none}}, + label_{}, required_{false}, greedy_{false} + { + add_flags(std::move(str), std::forward(strs)...); + } + + /** @brief makes "flag" parameter from range of strings */ + explicit + parameter(const arg_list& flaglist): + flags_{}, + matcher_{predicate_adapter{match::none}}, + label_{}, required_{false}, greedy_{false} + { + add_flags(flaglist); + } + + //----------------------------------------------------- + /** @brief makes "value" parameter with custom match predicate + * (= yes/no matcher) + */ + explicit + parameter(match_predicate filter): + flags_{}, + matcher_{predicate_adapter{std::move(filter)}}, + label_{}, required_{false}, greedy_{false} + {} + + /** @brief makes "value" parameter with custom match function + * (= partial matcher) + */ + explicit + parameter(match_function filter): + flags_{}, + matcher_{std::move(filter)}, + label_{}, required_{false}, greedy_{false} + {} + + + //--------------------------------------------------------------- + /** @brief returns if a parameter is required */ + bool + required() const noexcept { + return required_; + } + + /** @brief determines if a parameter is required */ + parameter& + required(bool yes) noexcept { + required_ = yes; + return *this; + } + + + //--------------------------------------------------------------- + /** @brief returns if a parameter should match greedily */ + bool + greedy() const noexcept { + return greedy_; + } + + /** @brief determines if a parameter should match greedily */ + parameter& + greedy(bool yes) noexcept { + greedy_ = yes; + return *this; + } + + + //--------------------------------------------------------------- + /** @brief returns parameter label; + * will be used for documentation, if flags are empty + */ + const doc_string& + label() const { + return label_; + } + + /** @brief sets parameter label; + * will be used for documentation, if flags are empty + */ + parameter& + label(const doc_string& lbl) { + label_ = lbl; + return *this; + } + + /** @brief sets parameter label; + * will be used for documentation, if flags are empty + */ + parameter& + label(doc_string&& lbl) { + label_ = lbl; + return *this; + } + + + //--------------------------------------------------------------- + /** @brief returns either longest matching prefix of 'arg' in any + * of the flags or the result of the custom match operation + */ + subrange + match(const arg_string& arg) const + { + if(flags_.empty()) { + return matcher_(arg); + } + else { + //empty flags are not allowed + if(arg.empty()) return subrange{}; + + if(std::find(flags_.begin(), flags_.end(), arg) != flags_.end()) { + return subrange{0,arg.size()}; + } + return str::longest_prefix_match(arg, flags_); + } + } + + + //--------------------------------------------------------------- + /** @brief access range of flag strings */ + const arg_list& + flags() const noexcept { + return flags_; + } + + /** @brief access custom match operation */ + const match_function& + matcher() const noexcept { + return matcher_; + } + + + //--------------------------------------------------------------- + /** @brief prepend prefix to each flag */ + inline friend parameter& + with_prefix(const arg_string& prefix, parameter& p) + { + if(prefix.empty() || p.flags().empty()) return p; + + for(auto& f : p.flags_) { + if(f.find(prefix) != 0) f.insert(0, prefix); + } + return p; + } + + + /** @brief prepend prefix to each flag + */ + inline friend parameter& + with_prefixes_short_long( + const arg_string& shortpfx, const arg_string& longpfx, + parameter& p) + { + if(shortpfx.empty() && longpfx.empty()) return p; + if(p.flags().empty()) return p; + + for(auto& f : p.flags_) { + if(f.size() == 1) { + if(f.find(shortpfx) != 0) f.insert(0, shortpfx); + } else { + if(f.find(longpfx) != 0) f.insert(0, longpfx); + } + } + return p; + } + + + //--------------------------------------------------------------- + /** @brief prepend suffix to each flag */ + inline friend parameter& + with_suffix(const arg_string& suffix, parameter& p) + { + if(suffix.empty() || p.flags().empty()) return p; + + for(auto& f : p.flags_) { + if(f.find(suffix) + suffix.size() != f.size()) { + f.insert(f.end(), suffix.begin(), suffix.end()); + } + } + return p; + } + + + /** @brief prepend suffix to each flag + */ + inline friend parameter& + with_suffixes_short_long( + const arg_string& shortsfx, const arg_string& longsfx, + parameter& p) + { + if(shortsfx.empty() && longsfx.empty()) return p; + if(p.flags().empty()) return p; + + for(auto& f : p.flags_) { + if(f.size() == 1) { + if(f.find(shortsfx) + shortsfx.size() != f.size()) { + f.insert(f.end(), shortsfx.begin(), shortsfx.end()); + } + } else { + if(f.find(longsfx) + longsfx.size() != f.size()) { + f.insert(f.end(), longsfx.begin(), longsfx.end()); + } + } + } + return p; + } + +private: + //--------------------------------------------------------------- + void add_flags(arg_string str) { + //empty flags are not allowed + str::remove_ws(str); + if(!str.empty()) flags_.push_back(std::move(str)); + } + + //--------------------------------------------------------------- + void add_flags(const arg_list& strs) { + if(strs.empty()) return; + flags_.reserve(flags_.size() + strs.size()); + for(const auto& s : strs) add_flags(s); + } + + template + void + add_flags(String1&& s1, String2&& s2, Strings&&... ss) { + flags_.reserve(2 + sizeof...(ss)); + add_flags(std::forward(s1)); + add_flags(std::forward(s2), std::forward(ss)...); + } + + arg_list flags_; + match_function matcher_; + doc_string label_; + bool required_ = false; + bool greedy_ = false; +}; + + + + +/*************************************************************************//** + * + * @brief makes required non-blocking exact match parameter + * + *****************************************************************************/ +template +inline parameter +command(String&& flag, Strings&&... flags) +{ + return parameter{std::forward(flag), std::forward(flags)...} + .required(true).blocking(true).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes required non-blocking exact match parameter + * + *****************************************************************************/ +template +inline parameter +required(String&& flag, Strings&&... flags) +{ + return parameter{std::forward(flag), std::forward(flags)...} + .required(true).blocking(false).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes optional, non-blocking exact match parameter + * + *****************************************************************************/ +template +inline parameter +option(String&& flag, Strings&&... flags) +{ + return parameter{std::forward(flag), std::forward(flags)...} + .required(false).blocking(false).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking, repeatable value parameter; + * matches any non-empty string + * + *****************************************************************************/ +template +inline parameter +value(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::nonempty} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(false); +} + +template::value || + traits::is_callable::value>::type> +inline parameter +value(Filter&& filter, doc_string label, Targets&&... tgts) +{ + return parameter{std::forward(filter)} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking, repeatable value parameter; + * matches any non-empty string + * + *****************************************************************************/ +template +inline parameter +values(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::nonempty} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(true); +} + +template::value || + traits::is_callable::value>::type> +inline parameter +values(Filter&& filter, doc_string label, Targets&&... tgts) +{ + return parameter{std::forward(filter)} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking value parameter; + * matches any non-empty string + * + *****************************************************************************/ +template +inline parameter +opt_value(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::nonempty} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(false); +} + +template::value || + traits::is_callable::value>::type> +inline parameter +opt_value(Filter&& filter, doc_string label, Targets&&... tgts) +{ + return parameter{std::forward(filter)} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking, repeatable value parameter; + * matches any non-empty string + * + *****************************************************************************/ +template +inline parameter +opt_values(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::nonempty} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(true); +} + +template::value || + traits::is_callable::value>::type> +inline parameter +opt_values(Filter&& filter, doc_string label, Targets&&... tgts) +{ + return parameter{std::forward(filter)} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking value parameter; + * matches any string consisting of alphanumeric characters + * + *****************************************************************************/ +template +inline parameter +word(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::alphanumeric} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking, repeatable value parameter; + * matches any string consisting of alphanumeric characters + * + *****************************************************************************/ +template +inline parameter +words(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::alphanumeric} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking value parameter; + * matches any string consisting of alphanumeric characters + * + *****************************************************************************/ +template +inline parameter +opt_word(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::alphanumeric} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking, repeatable value parameter; + * matches any string consisting of alphanumeric characters + * + *****************************************************************************/ +template +inline parameter +opt_words(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::alphanumeric} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking value parameter; + * matches any string that represents a number + * + *****************************************************************************/ +template +inline parameter +number(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::numbers{}} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking, repeatable value parameter; + * matches any string that represents a number + * + *****************************************************************************/ +template +inline parameter +numbers(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::numbers{}} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking value parameter; + * matches any string that represents a number + * + *****************************************************************************/ +template +inline parameter +opt_number(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::numbers{}} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking, repeatable value parameter; + * matches any string that represents a number + * + *****************************************************************************/ +template +inline parameter +opt_numbers(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::numbers{}} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking value parameter; + * matches any string that represents an integer + * + *****************************************************************************/ +template +inline parameter +integer(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::integers{}} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes required, blocking, repeatable value parameter; + * matches any string that represents an integer + * + *****************************************************************************/ +template +inline parameter +integers(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::integers{}} + .label(label) + .target(std::forward(tgts)...) + .required(true).blocking(true).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking value parameter; + * matches any string that represents an integer + * + *****************************************************************************/ +template +inline parameter +opt_integer(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::integers{}} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(false); +} + + + +/*************************************************************************//** + * + * @brief makes optional, blocking, repeatable value parameter; + * matches any string that represents an integer + * + *****************************************************************************/ +template +inline parameter +opt_integers(const doc_string& label, Targets&&... tgts) +{ + return parameter{match::integers{}} + .label(label) + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes catch-all value parameter + * + *****************************************************************************/ +template +inline parameter +any_other(Targets&&... tgts) +{ + return parameter{match::any} + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes catch-all value parameter with custom filter + * + *****************************************************************************/ +template::value || + traits::is_callable::value>::type> +inline parameter +any(Filter&& filter, Targets&&... tgts) +{ + return parameter{std::forward(filter)} + .target(std::forward(tgts)...) + .required(false).blocking(false).repeatable(true); +} + + + + +/*************************************************************************//** + * + * @brief group of parameters and/or other groups; + * can be configured to act as a group of alternatives (exclusive match) + * + *****************************************************************************/ +class group : + public detail::token +{ + //--------------------------------------------------------------- + /** + * @brief tagged union type that either stores a parameter or a group + * and provides a common interface to them + * could be replaced by std::variant in the future + * + * Note to future self: do NOT try again to do this with + * dynamic polymorphism; there are a couple of + * nasty problems associated with it and the implementation + * becomes bloated and needlessly complicated. + */ + template + struct child_t { + enum class type : char {param, group}; + public: + + explicit + child_t(const Param& v) : m_{v}, type_{type::param} {} + child_t( Param&& v) noexcept : m_{std::move(v)}, type_{type::param} {} + + explicit + child_t(const Group& g) : m_{g}, type_{type::group} {} + child_t( Group&& g) noexcept : m_{std::move(g)}, type_{type::group} {} + + child_t(const child_t& src): type_{src.type_} { + switch(type_) { + default: + case type::param: new(&m_)data{src.m_.param}; break; + case type::group: new(&m_)data{src.m_.group}; break; + } + } + + child_t(child_t&& src) noexcept : type_{src.type_} { + switch(type_) { + default: + case type::param: new(&m_)data{std::move(src.m_.param)}; break; + case type::group: new(&m_)data{std::move(src.m_.group)}; break; + } + } + + child_t& operator = (const child_t& src) { + destroy_content(); + type_ = src.type_; + switch(type_) { + default: + case type::param: new(&m_)data{src.m_.param}; break; + case type::group: new(&m_)data{src.m_.group}; break; + } + return *this; + } + + child_t& operator = (child_t&& src) noexcept { + destroy_content(); + type_ = src.type_; + switch(type_) { + default: + case type::param: new(&m_)data{std::move(src.m_.param)}; break; + case type::group: new(&m_)data{std::move(src.m_.group)}; break; + } + return *this; + } + + ~child_t() { + destroy_content(); + } + + const doc_string& + doc() const noexcept { + switch(type_) { + default: + case type::param: return m_.param.doc(); + case type::group: return m_.group.doc(); + } + } + + bool blocking() const noexcept { + switch(type_) { + case type::param: return m_.param.blocking(); + case type::group: return m_.group.blocking(); + default: return false; + } + } + bool repeatable() const noexcept { + switch(type_) { + case type::param: return m_.param.repeatable(); + case type::group: return m_.group.repeatable(); + default: return false; + } + } + bool required() const noexcept { + switch(type_) { + case type::param: return m_.param.required(); + case type::group: + return (m_.group.exclusive() && m_.group.all_required() ) || + (!m_.group.exclusive() && m_.group.any_required() ); + default: return false; + } + } + bool exclusive() const noexcept { + switch(type_) { + case type::group: return m_.group.exclusive(); + case type::param: + default: return false; + } + } + std::size_t param_count() const noexcept { + switch(type_) { + case type::group: return m_.group.param_count(); + case type::param: + default: return std::size_t(1); + } + } + std::size_t depth() const noexcept { + switch(type_) { + case type::group: return m_.group.depth(); + case type::param: + default: return std::size_t(0); + } + } + + void execute_actions(const arg_string& arg) const { + switch(type_) { + default: + case type::group: return; + case type::param: m_.param.execute_actions(arg); break; + } + + } + + void notify_repeated(arg_index idx) const { + switch(type_) { + default: + case type::group: return; + case type::param: m_.param.notify_repeated(idx); break; + } + } + void notify_missing(arg_index idx) const { + switch(type_) { + default: + case type::group: return; + case type::param: m_.param.notify_missing(idx); break; + } + } + void notify_blocked(arg_index idx) const { + switch(type_) { + default: + case type::group: return; + case type::param: m_.param.notify_blocked(idx); break; + } + } + void notify_conflict(arg_index idx) const { + switch(type_) { + default: + case type::group: return; + case type::param: m_.param.notify_conflict(idx); break; + } + } + + bool is_param() const noexcept { return type_ == type::param; } + bool is_group() const noexcept { return type_ == type::group; } + + Param& as_param() noexcept { return m_.param; } + Group& as_group() noexcept { return m_.group; } + + const Param& as_param() const noexcept { return m_.param; } + const Group& as_group() const noexcept { return m_.group; } + + private: + void destroy_content() { + switch(type_) { + default: + case type::param: m_.param.~Param(); break; + case type::group: m_.group.~Group(); break; + } + } + + union data { + data() {} + + data(const Param& v) : param{v} {} + data( Param&& v) noexcept : param{std::move(v)} {} + + data(const Group& g) : group{g} {} + data( Group&& g) noexcept : group{std::move(g)} {} + ~data() {} + + Param param; + Group group; + }; + + data m_; + type type_; + }; + + +public: + //--------------------------------------------------------------- + using child = child_t; + using value_type = child; + +private: + using children_store = std::vector; + +public: + using const_iterator = children_store::const_iterator; + using iterator = children_store::iterator; + using size_type = children_store::size_type; + + + //--------------------------------------------------------------- + /** + * @brief recursively iterates over all nodes + */ + class depth_first_traverser + { + public: + //----------------------------------------------------- + struct context { + context() = default; + context(const group& p): + parent{&p}, cur{p.begin()}, end{p.end()} + {} + const group* parent = nullptr; + const_iterator cur; + const_iterator end; + }; + using context_list = std::vector; + + //----------------------------------------------------- + class memento { + friend class depth_first_traverser; + int level_; + context context_; + public: + int level() const noexcept { return level_; } + const child* param() const noexcept { return &(*context_.cur); } + }; + + depth_first_traverser() = default; + + explicit + depth_first_traverser(const group& cur): stack_{} { + if(!cur.empty()) stack_.emplace_back(cur); + } + + explicit operator bool() const noexcept { + return !stack_.empty(); + } + + int level() const noexcept { + return int(stack_.size()); + } + + bool is_first_in_parent() const noexcept { + if(stack_.empty()) return false; + return (stack_.back().cur == stack_.back().parent->begin()); + } + + bool is_last_in_parent() const noexcept { + if(stack_.empty()) return false; + return (stack_.back().cur+1 == stack_.back().end); + } + + bool is_last_in_path() const noexcept { + if(stack_.empty()) return false; + for(const auto& t : stack_) { + if(t.cur+1 != t.end) return false; + } + const auto& top = stack_.back(); + //if we have to descend into group on next ++ => not last in path + if(top.cur->is_group()) return false; + return true; + } + + /** @brief inside a group of alternatives >= minlevel */ + bool is_alternative(int minlevel = 0) const noexcept { + if(stack_.empty()) return false; + if(minlevel > 0) minlevel -= 1; + if(minlevel >= int(stack_.size())) return false; + return std::any_of(stack_.begin() + minlevel, stack_.end(), + [](const context& c) { return c.parent->exclusive(); }); + } + + /** @brief repeatable or inside a repeatable group >= minlevel */ + bool is_repeatable(int minlevel = 0) const noexcept { + if(stack_.empty()) return false; + if(stack_.back().cur->repeatable()) return true; + if(minlevel > 0) minlevel -= 1; + if(minlevel >= int(stack_.size())) return false; + return std::any_of(stack_.begin() + minlevel, stack_.end(), + [](const context& c) { return c.parent->repeatable(); }); + } + + /** @brief inside a particular group */ + bool is_inside(const group* g) const noexcept { + if(!g) return false; + return std::any_of(stack_.begin(), stack_.end(), + [g](const context& c) { return c.parent == g; }); + } + + /** @brief inside group with joinable flags */ + bool joinable() const noexcept { + if(stack_.empty()) return false; + return std::any_of(stack_.begin(), stack_.end(), + [](const context& c) { return c.parent->joinable(); }); + } + + const context_list& + stack() const { + return stack_; + } + + /** @brief innermost repeat group */ + const group* + innermost_repeat_group() const noexcept { + auto i = std::find_if(stack_.rbegin(), stack_.rend(), + [](const context& c) { return c.parent->repeatable(); }); + return i != stack_.rend() ? i->parent : nullptr; + } + + /** @brief innermost exclusive (alternatives) group */ + const group* + innermost_exclusive_group() const noexcept { + auto i = std::find_if(stack_.rbegin(), stack_.rend(), + [](const context& c) { return c.parent->exclusive(); }); + return i != stack_.rend() ? i->parent : nullptr; + } + + /** @brief innermost blocking group */ + const group* + innermost_blocking_group() const noexcept { + auto i = std::find_if(stack_.rbegin(), stack_.rend(), + [](const context& c) { return c.parent->blocking(); }); + return i != stack_.rend() ? i->parent : nullptr; + } + + /** @brief returns the outermost group that will be left on next ++*/ + const group* + outermost_blocking_group_fully_explored() const noexcept { + if(stack_.empty()) return nullptr; + + const group* g = nullptr; + for(auto i = stack_.rbegin(); i != stack_.rend(); ++i) { + if(i->cur+1 == i->end) { + if(i->parent->blocking()) g = i->parent; + } else { + return g; + } + } + return g; + } + + /** @brief outermost join group */ + const group* + outermost_join_group() const noexcept { + auto i = std::find_if(stack_.begin(), stack_.end(), + [](const context& c) { return c.parent->joinable(); }); + return i != stack_.end() ? i->parent : nullptr; + } + + const group* root() const noexcept { + return stack_.empty() ? nullptr : stack_.front().parent; + } + + /** @brief common flag prefix of all flags in current group */ + arg_string common_flag_prefix() const noexcept { + if(stack_.empty()) return ""; + auto g = outermost_join_group(); + return g ? g->common_flag_prefix() : arg_string(""); + } + + const child& + operator * () const noexcept { + return *stack_.back().cur; + } + + const child* + operator -> () const noexcept { + return &(*stack_.back().cur); + } + + const group& + parent() const noexcept { + return *(stack_.back().parent); + } + + + /** @brief go to next element of depth first search */ + depth_first_traverser& + operator ++ () { + if(stack_.empty()) return *this; + //at group -> decend into group + if(stack_.back().cur->is_group()) { + stack_.emplace_back(stack_.back().cur->as_group()); + } + else { + next_sibling(); + } + return *this; + } + + /** @brief go to next sibling of current */ + depth_first_traverser& + next_sibling() { + if(stack_.empty()) return *this; + ++stack_.back().cur; + //at the end of current group? + while(stack_.back().cur == stack_.back().end) { + //go to parent + stack_.pop_back(); + if(stack_.empty()) return *this; + //go to next sibling in parent + ++stack_.back().cur; + } + return *this; + } + + /** @brief go to next position after siblings of current */ + depth_first_traverser& + next_after_siblings() { + if(stack_.empty()) return *this; + stack_.back().cur = stack_.back().end-1; + next_sibling(); + return *this; + } + + /** + * @brief + */ + depth_first_traverser& + back_to_ancestor(const group* g) { + if(!g) return *this; + while(!stack_.empty()) { + const auto& top = stack_.back().cur; + if(top->is_group() && &(top->as_group()) == g) return *this; + stack_.pop_back(); + } + return *this; + } + + /** @brief don't visit next siblings, go back to parent on next ++ + * note: renders siblings unreachable for *this + **/ + depth_first_traverser& + skip_siblings() { + if(stack_.empty()) return *this; + //future increments won't visit subsequent siblings: + stack_.back().end = stack_.back().cur+1; + return *this; + } + + /** @brief skips all other alternatives in surrounding exclusive groups + * on next ++ + * note: renders alternatives unreachable for *this + */ + depth_first_traverser& + skip_alternatives() { + if(stack_.empty()) return *this; + + //exclude all other alternatives in surrounding groups + //by making their current position the last one + for(auto& c : stack_) { + if(c.parent && c.parent->exclusive() && c.cur < c.end) + c.end = c.cur+1; + } + + return *this; + } + + void invalidate() { + stack_.clear(); + } + + inline friend bool operator == (const depth_first_traverser& a, + const depth_first_traverser& b) + { + if(a.stack_.empty() || b.stack_.empty()) return false; + + //parents not the same -> different position + if(a.stack_.back().parent != b.stack_.back().parent) return false; + + bool aEnd = a.stack_.back().cur == a.stack_.back().end; + bool bEnd = b.stack_.back().cur == b.stack_.back().end; + //either both at the end of the same parent => same position + if(aEnd && bEnd) return true; + //or only one at the end => not at the same position + if(aEnd || bEnd) return false; + return std::addressof(*a.stack_.back().cur) == + std::addressof(*b.stack_.back().cur); + } + inline friend bool operator != (const depth_first_traverser& a, + const depth_first_traverser& b) + { + return !(a == b); + } + + memento + undo_point() const { + memento m; + m.level_ = int(stack_.size()); + if(!stack_.empty()) m.context_ = stack_.back(); + return m; + } + + void undo(const memento& m) { + if(m.level_ < 1) return; + if(m.level_ <= int(stack_.size())) { + stack_.erase(stack_.begin() + m.level_, stack_.end()); + stack_.back() = m.context_; + } + else if(stack_.empty() && m.level_ == 1) { + stack_.push_back(m.context_); + } + } + + private: + context_list stack_; + }; + + + //--------------------------------------------------------------- + group() = default; + + template + explicit + group(doc_string docstr, Param param, Params... params): + children_{}, exclusive_{false}, joinable_{false}, scoped_{true} + { + doc(std::move(docstr)); + push_back(std::move(param), std::move(params)...); + } + + template + explicit + group(parameter param, Params... params): + children_{}, exclusive_{false}, joinable_{false}, scoped_{true} + { + push_back(std::move(param), std::move(params)...); + } + + template + explicit + group(group p1, P2 p2, Ps... ps): + children_{}, exclusive_{false}, joinable_{false}, scoped_{true} + { + push_back(std::move(p1), std::move(p2), std::move(ps)...); + } + + + //----------------------------------------------------- + group(const group&) = default; + group(group&&) = default; + + + //--------------------------------------------------------------- + group& operator = (const group&) = default; + group& operator = (group&&) = default; + + + //--------------------------------------------------------------- + /** @brief determines if a command line argument can be matched by a + * combination of (partial) matches through any number of children + */ + group& joinable(bool yes) { + joinable_ = yes; + return *this; + } + + /** @brief returns if a command line argument can be matched by a + * combination of (partial) matches through any number of children + */ + bool joinable() const noexcept { + return joinable_; + } + + + //--------------------------------------------------------------- + /** @brief turns explicit scoping on or off + * operators , & | and other combinating functions will + * not merge groups that are marked as scoped + */ + group& scoped(bool yes) { + scoped_ = yes; + return *this; + } + + /** @brief returns true if operators , & | and other combinating functions + * will merge groups and false otherwise + */ + bool scoped() const noexcept + { + return scoped_; + } + + + //--------------------------------------------------------------- + /** @brief determines if children are mutually exclusive alternatives */ + group& exclusive(bool yes) { + exclusive_ = yes; + return *this; + } + /** @brief returns if children are mutually exclusive alternatives */ + bool exclusive() const noexcept { + return exclusive_; + } + + + //--------------------------------------------------------------- + /** @brief returns true, if any child is required to match */ + bool any_required() const + { + return std::any_of(children_.begin(), children_.end(), + [](const child& n){ return n.required(); }); + } + /** @brief returns true, if all children are required to match */ + bool all_required() const + { + return std::all_of(children_.begin(), children_.end(), + [](const child& n){ return n.required(); }); + } + + + //--------------------------------------------------------------- + /** @brief returns true if any child is optional (=non-required) */ + bool any_optional() const { + return !all_required(); + } + /** @brief returns true if all children are optional (=non-required) */ + bool all_optional() const { + return !any_required(); + } + + + //--------------------------------------------------------------- + /** @brief returns if the entire group is blocking / positional */ + bool blocking() const noexcept { + return token::blocking() || (exclusive() && all_blocking()); + } + //----------------------------------------------------- + /** @brief determines if the entire group is blocking / positional */ + group& blocking(bool yes) { + return token::blocking(yes); + } + + //--------------------------------------------------------------- + /** @brief returns true if any child is blocking */ + bool any_blocking() const + { + return std::any_of(children_.begin(), children_.end(), + [](const child& n){ return n.blocking(); }); + } + //--------------------------------------------------------------- + /** @brief returns true if all children is blocking */ + bool all_blocking() const + { + return std::all_of(children_.begin(), children_.end(), + [](const child& n){ return n.blocking(); }); + } + + + //--------------------------------------------------------------- + /** @brief returns if any child is a value parameter (recursive) */ + bool any_flagless() const + { + return std::any_of(children_.begin(), children_.end(), + [](const child& p){ + return p.is_param() && p.as_param().flags().empty(); + }); + } + /** @brief returns if all children are value parameters (recursive) */ + bool all_flagless() const + { + return std::all_of(children_.begin(), children_.end(), + [](const child& p){ + return p.is_param() && p.as_param().flags().empty(); + }); + } + + + //--------------------------------------------------------------- + /** @brief adds child parameter at the end */ + group& + push_back(const parameter& v) { + children_.emplace_back(v); + return *this; + } + //----------------------------------------------------- + /** @brief adds child parameter at the end */ + group& + push_back(parameter&& v) { + children_.emplace_back(std::move(v)); + return *this; + } + //----------------------------------------------------- + /** @brief adds child group at the end */ + group& + push_back(const group& g) { + children_.emplace_back(g); + return *this; + } + //----------------------------------------------------- + /** @brief adds child group at the end */ + group& + push_back(group&& g) { + children_.emplace_back(std::move(g)); + return *this; + } + + + //----------------------------------------------------- + /** @brief adds children (groups and/or parameters) */ + template + group& + push_back(Param1&& param1, Param2&& param2, Params&&... params) + { + children_.reserve(children_.size() + 2 + sizeof...(params)); + push_back(std::forward(param1)); + push_back(std::forward(param2), std::forward(params)...); + return *this; + } + + + //--------------------------------------------------------------- + /** @brief adds child parameter at the beginning */ + group& + push_front(const parameter& v) { + children_.emplace(children_.begin(), v); + return *this; + } + //----------------------------------------------------- + /** @brief adds child parameter at the beginning */ + group& + push_front(parameter&& v) { + children_.emplace(children_.begin(), std::move(v)); + return *this; + } + //----------------------------------------------------- + /** @brief adds child group at the beginning */ + group& + push_front(const group& g) { + children_.emplace(children_.begin(), g); + return *this; + } + //----------------------------------------------------- + /** @brief adds child group at the beginning */ + group& + push_front(group&& g) { + children_.emplace(children_.begin(), std::move(g)); + return *this; + } + + + //--------------------------------------------------------------- + /** @brief adds all children of other group at the end */ + group& + merge(group&& g) + { + children_.insert(children_.end(), + std::make_move_iterator(g.begin()), + std::make_move_iterator(g.end())); + return *this; + } + //----------------------------------------------------- + /** @brief adds all children of several other groups at the end */ + template + group& + merge(group&& g1, group&& g2, Groups&&... gs) + { + merge(std::move(g1)); + merge(std::move(g2), std::forward(gs)...); + return *this; + } + + + //--------------------------------------------------------------- + /** @brief indexed, nutable access to child */ + child& operator [] (size_type index) noexcept { + return children_[index]; + } + /** @brief indexed, non-nutable access to child */ + const child& operator [] (size_type index) const noexcept { + return children_[index]; + } + + //--------------------------------------------------------------- + /** @brief mutable access to first child */ + child& front() noexcept { return children_.front(); } + /** @brief non-mutable access to first child */ + const child& front() const noexcept { return children_.front(); } + //----------------------------------------------------- + /** @brief mutable access to last child */ + child& back() noexcept { return children_.back(); } + /** @brief non-mutable access to last child */ + const child& back() const noexcept { return children_.back(); } + + + //--------------------------------------------------------------- + /** @brief returns true, if group has no children, false otherwise */ + bool empty() const noexcept { return children_.empty(); } + + /** @brief returns number of children */ + size_type size() const noexcept { return children_.size(); } + + /** @brief returns number of nested levels; 1 for a flat group */ + size_type depth() const { + size_type n = 0; + for(const auto& c : children_) { + auto l = 1 + c.depth(); + if(l > n) n = l; + } + return n; + } + + + //--------------------------------------------------------------- + /** @brief returns mutating iterator to position of first element */ + iterator begin() noexcept { return children_.begin(); } + /** @brief returns non-mutating iterator to position of first element */ + const_iterator begin() const noexcept { return children_.begin(); } + /** @brief returns non-mutating iterator to position of first element */ + const_iterator cbegin() const noexcept { return children_.begin(); } + + /** @brief returns mutating iterator to position one past the last element */ + iterator end() noexcept { return children_.end(); } + /** @brief returns non-mutating iterator to position one past the last element */ + const_iterator end() const noexcept { return children_.end(); } + /** @brief returns non-mutating iterator to position one past the last element */ + const_iterator cend() const noexcept { return children_.end(); } + + + //--------------------------------------------------------------- + /** @brief returns augmented iterator for depth first searches + * @details traverser knows end of iteration and can skip over children + */ + depth_first_traverser + begin_dfs() const noexcept { + return depth_first_traverser{*this}; + } + + + //--------------------------------------------------------------- + /** @brief returns recursive parameter count */ + size_type param_count() const { + size_type c = 0; + for(const auto& n : children_) { + c += n.param_count(); + } + return c; + } + + + //--------------------------------------------------------------- + /** @brief returns range of all flags (recursive) */ + arg_list all_flags() const + { + std::vector all; + gather_flags(children_, all); + return all; + } + + /** @brief returns true, if no flag occurs as true + * prefix of any other flag (identical flags will be ignored) */ + bool flags_are_prefix_free() const + { + const auto fs = all_flags(); + + using std::begin; using std::end; + for(auto i = begin(fs), e = end(fs); i != e; ++i) { + if(!i->empty()) { + for(auto j = i+1; j != e; ++j) { + if(!j->empty() && *i != *j) { + if(i->find(*j) == 0) return false; + if(j->find(*i) == 0) return false; + } + } + } + } + + return true; + } + + + //--------------------------------------------------------------- + /** @brief returns longest common prefix of all flags */ + arg_string common_flag_prefix() const + { + arg_list prefixes; + gather_prefixes(children_, prefixes); + return str::longest_common_prefix(prefixes); + } + + +private: + //--------------------------------------------------------------- + static void + gather_flags(const children_store& nodes, arg_list& all) + { + for(const auto& p : nodes) { + if(p.is_group()) { + gather_flags(p.as_group().children_, all); + } + else { + const auto& pf = p.as_param().flags(); + using std::begin; + using std::end; + if(!pf.empty()) all.insert(end(all), begin(pf), end(pf)); + } + } + } + //--------------------------------------------------------------- + static void + gather_prefixes(const children_store& nodes, arg_list& all) + { + for(const auto& p : nodes) { + if(p.is_group()) { + gather_prefixes(p.as_group().children_, all); + } + else if(!p.as_param().flags().empty()) { + auto pfx = str::longest_common_prefix(p.as_param().flags()); + if(!pfx.empty()) all.push_back(std::move(pfx)); + } + } + } + + //--------------------------------------------------------------- + children_store children_; + bool exclusive_ = false; + bool joinable_ = false; + bool scoped_ = false; +}; + + + +/*************************************************************************//** + * + * @brief group or parameter + * + *****************************************************************************/ +using pattern = group::child; + + + +/*************************************************************************//** + * + * @brief apply an action to all parameters in a group + * + *****************************************************************************/ +template +void for_all_params(group& g, Action&& action) +{ + for(auto& p : g) { + if(p.is_group()) { + for_all_params(p.as_group(), action); + } + else { + action(p.as_param()); + } + } +} + +template +void for_all_params(const group& g, Action&& action) +{ + for(auto& p : g) { + if(p.is_group()) { + for_all_params(p.as_group(), action); + } + else { + action(p.as_param()); + } + } +} + + + +/*************************************************************************//** + * + * @brief makes a group of parameters and/or groups + * + *****************************************************************************/ +inline group +operator , (parameter a, parameter b) +{ + return group{std::move(a), std::move(b)}.scoped(false); +} + +//--------------------------------------------------------- +inline group +operator , (parameter a, group b) +{ + return !b.scoped() && !b.blocking() && !b.exclusive() && !b.repeatable() + && !b.joinable() && (b.doc().empty() || b.doc() == a.doc()) + ? b.push_front(std::move(a)) + : group{std::move(a), std::move(b)}.scoped(false); +} + +//--------------------------------------------------------- +inline group +operator , (group a, parameter b) +{ + return !a.scoped() && !a.blocking() && !a.exclusive() && !a.repeatable() + && !a.joinable() && (a.doc().empty() || a.doc() == b.doc()) + ? a.push_back(std::move(b)) + : group{std::move(a), std::move(b)}.scoped(false); +} + +//--------------------------------------------------------- +inline group +operator , (group a, group b) +{ + return !a.scoped() && !a.blocking() && !a.exclusive() && !a.repeatable() + && !a.joinable() && (a.doc().empty() || a.doc() == b.doc()) + ? a.push_back(std::move(b)) + : group{std::move(a), std::move(b)}.scoped(false); +} + + + +/*************************************************************************//** + * + * @brief makes a group of alternative parameters or groups + * + *****************************************************************************/ +template +inline group +one_of(Param param, Params... params) +{ + return group{std::move(param), std::move(params)...}.exclusive(true); +} + + +/*************************************************************************//** + * + * @brief makes a group of alternative parameters or groups + * + *****************************************************************************/ +inline group +operator | (parameter a, parameter b) +{ + return group{std::move(a), std::move(b)}.scoped(false).exclusive(true); +} + +//------------------------------------------------------------------- +inline group +operator | (parameter a, group b) +{ + return !b.scoped() && !b.blocking() && b.exclusive() && !b.repeatable() + && !b.joinable() + && (b.doc().empty() || b.doc() == a.doc()) + ? b.push_front(std::move(a)) + : group{std::move(a), std::move(b)}.scoped(false).exclusive(true); +} + +//------------------------------------------------------------------- +inline group +operator | (group a, parameter b) +{ + return !a.scoped() && a.exclusive() && !a.repeatable() && !a.joinable() + && a.blocking() == b.blocking() + && (a.doc().empty() || a.doc() == b.doc()) + ? a.push_back(std::move(b)) + : group{std::move(a), std::move(b)}.scoped(false).exclusive(true); +} + +inline group +operator | (group a, group b) +{ + return !a.scoped() && a.exclusive() &&!a.repeatable() && !a.joinable() + && a.blocking() == b.blocking() + && (a.doc().empty() || a.doc() == b.doc()) + ? a.push_back(std::move(b)) + : group{std::move(a), std::move(b)}.scoped(false).exclusive(true); +} + + + +/*************************************************************************//** + * + * @brief helpers (NOT FOR DIRECT USE IN CLIENT CODE!) + * no interface guarantees; might be changed or removed in the future + * + *****************************************************************************/ +namespace detail { + +inline void set_blocking(bool) {} + +template +void set_blocking(bool yes, P& p, Ps&... ps) { + p.blocking(yes); + set_blocking(yes, ps...); +} + +} // namespace detail + + +/*************************************************************************//** + * + * @brief makes a parameter/group sequence by making all input objects blocking + * + *****************************************************************************/ +template +inline group +in_sequence(Param param, Params... params) +{ + detail::set_blocking(true, param, params...); + return group{std::move(param), std::move(params)...}.scoped(true); +} + + +/*************************************************************************//** + * + * @brief makes a parameter/group sequence by making all input objects blocking + * + *****************************************************************************/ +inline group +operator & (parameter a, parameter b) +{ + a.blocking(true); + b.blocking(true); + return group{std::move(a), std::move(b)}.scoped(true); +} + +//--------------------------------------------------------- +inline group +operator & (parameter a, group b) +{ + a.blocking(true); + return group{std::move(a), std::move(b)}.scoped(true); +} + +//--------------------------------------------------------- +inline group +operator & (group a, parameter b) +{ + b.blocking(true); + if(a.all_blocking() && !a.exclusive() && !a.repeatable() && !a.joinable() + && (a.doc().empty() || a.doc() == b.doc())) + { + return a.push_back(std::move(b)); + } + else { + if(!a.all_blocking()) a.blocking(true); + return group{std::move(a), std::move(b)}.scoped(true); + } +} + +inline group +operator & (group a, group b) +{ + if(!b.all_blocking()) b.blocking(true); + if(a.all_blocking() && !a.exclusive() && !a.repeatable() + && !a.joinable() && (a.doc().empty() || a.doc() == b.doc())) + { + return a.push_back(std::move(b)); + } + else { + if(!a.all_blocking()) a.blocking(true); + return group{std::move(a), std::move(b)}.scoped(true); + } +} + + + +/*************************************************************************//** + * + * @brief makes a group of parameters and/or groups + * where all single char flag params ("-a", "b", ...) are joinable + * + *****************************************************************************/ +inline group +joinable(group g) { + return g.joinable(true); +} + +//------------------------------------------------------------------- +template +inline group +joinable(parameter param, Params... params) +{ + return group{std::move(param), std::move(params)...}.joinable(true); +} + +template +inline group +joinable(group p1, P2 p2, Ps... ps) +{ + return group{std::move(p1), std::move(p2), std::move(ps)...}.joinable(true); +} + +template +inline group +joinable(doc_string docstr, Param param, Params... params) +{ + return group{std::move(param), std::move(params)...} + .joinable(true).doc(std::move(docstr)); +} + + + +/*************************************************************************//** + * + * @brief makes a repeatable copy of a parameter + * + *****************************************************************************/ +inline parameter +repeatable(parameter p) { + return p.repeatable(true); +} + +/*************************************************************************//** + * + * @brief makes a repeatable copy of a group + * + *****************************************************************************/ +inline group +repeatable(group g) { + return g.repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes a group of parameters and/or groups + * that is repeatable as a whole + * Note that a repeatable group consisting entirely of non-blocking + * children is equivalent to a non-repeatable group of + * repeatable children. + * + *****************************************************************************/ +template +inline group +repeatable(parameter p1, P2 p2, Ps... ps) +{ + return group{std::move(p1), std::move(p2), + std::move(ps)...}.repeatable(true); +} + +template +inline group +repeatable(group p1, P2 p2, Ps... ps) +{ + return group{std::move(p1), std::move(p2), + std::move(ps)...}.repeatable(true); +} + + + +/*************************************************************************//** + * + * @brief makes a parameter greedy (match with top priority) + * + *****************************************************************************/ +inline parameter +greedy(parameter p) { + return p.greedy(true); +} + +inline parameter +operator ! (parameter p) { + return greedy(p); +} + + + +/*************************************************************************//** + * + * @brief recursively prepends a prefix to all flags + * + *****************************************************************************/ +inline parameter&& +with_prefix(const arg_string& prefix, parameter&& p) { + return std::move(with_prefix(prefix, p)); +} + + +//------------------------------------------------------------------- +inline group& +with_prefix(const arg_string& prefix, group& g) +{ + for(auto& p : g) { + if(p.is_group()) { + with_prefix(prefix, p.as_group()); + } else { + with_prefix(prefix, p.as_param()); + } + } + return g; +} + + +inline group&& +with_prefix(const arg_string& prefix, group&& params) +{ + return std::move(with_prefix(prefix, params)); +} + + +template +inline group +with_prefix(arg_string prefix, Param&& param, Params&&... params) +{ + return with_prefix(prefix, group{std::forward(param), + std::forward(params)...}); +} + + + +/*************************************************************************//** + * + * @brief recursively prepends a prefix to all flags + * + * @param shortpfx : used for single-letter flags + * @param longpfx : used for flags with length > 1 + * + *****************************************************************************/ +inline parameter&& +with_prefixes_short_long(const arg_string& shortpfx, const arg_string& longpfx, + parameter&& p) +{ + return std::move(with_prefixes_short_long(shortpfx, longpfx, p)); +} + + +//------------------------------------------------------------------- +inline group& +with_prefixes_short_long(const arg_string& shortFlagPrefix, + const arg_string& longFlagPrefix, + group& g) +{ + for(auto& p : g) { + if(p.is_group()) { + with_prefixes_short_long(shortFlagPrefix, longFlagPrefix, p.as_group()); + } else { + with_prefixes_short_long(shortFlagPrefix, longFlagPrefix, p.as_param()); + } + } + return g; +} + + +inline group&& +with_prefixes_short_long(const arg_string& shortFlagPrefix, + const arg_string& longFlagPrefix, + group&& params) +{ + return std::move(with_prefixes_short_long(shortFlagPrefix, longFlagPrefix, + params)); +} + + +template +inline group +with_prefixes_short_long(const arg_string& shortFlagPrefix, + const arg_string& longFlagPrefix, + Param&& param, Params&&... params) +{ + return with_prefixes_short_long(shortFlagPrefix, longFlagPrefix, + group{std::forward(param), + std::forward(params)...}); +} + + + +/*************************************************************************//** + * + * @brief recursively prepends a suffix to all flags + * + *****************************************************************************/ +inline parameter&& +with_suffix(const arg_string& suffix, parameter&& p) { + return std::move(with_suffix(suffix, p)); +} + + +//------------------------------------------------------------------- +inline group& +with_suffix(const arg_string& suffix, group& g) +{ + for(auto& p : g) { + if(p.is_group()) { + with_suffix(suffix, p.as_group()); + } else { + with_suffix(suffix, p.as_param()); + } + } + return g; +} + + +inline group&& +with_suffix(const arg_string& suffix, group&& params) +{ + return std::move(with_suffix(suffix, params)); +} + + +template +inline group +with_suffix(arg_string suffix, Param&& param, Params&&... params) +{ + return with_suffix(suffix, group{std::forward(param), + std::forward(params)...}); +} + + + +/*************************************************************************//** + * + * @brief recursively prepends a suffix to all flags + * + * @param shortsfx : used for single-letter flags + * @param longsfx : used for flags with length > 1 + * + *****************************************************************************/ +inline parameter&& +with_suffixes_short_long(const arg_string& shortsfx, const arg_string& longsfx, + parameter&& p) +{ + return std::move(with_suffixes_short_long(shortsfx, longsfx, p)); +} + + +//------------------------------------------------------------------- +inline group& +with_suffixes_short_long(const arg_string& shortFlagSuffix, + const arg_string& longFlagSuffix, + group& g) +{ + for(auto& p : g) { + if(p.is_group()) { + with_suffixes_short_long(shortFlagSuffix, longFlagSuffix, p.as_group()); + } else { + with_suffixes_short_long(shortFlagSuffix, longFlagSuffix, p.as_param()); + } + } + return g; +} + + +inline group&& +with_suffixes_short_long(const arg_string& shortFlagSuffix, + const arg_string& longFlagSuffix, + group&& params) +{ + return std::move(with_suffixes_short_long(shortFlagSuffix, longFlagSuffix, + params)); +} + + +template +inline group +with_suffixes_short_long(const arg_string& shortFlagSuffix, + const arg_string& longFlagSuffix, + Param&& param, Params&&... params) +{ + return with_suffixes_short_long(shortFlagSuffix, longFlagSuffix, + group{std::forward(param), + std::forward(params)...}); +} + + + + + + + + +/*************************************************************************//** + * + * @brief parsing implementation details + * + *****************************************************************************/ + +namespace detail { + + +/*************************************************************************//** + * + * @brief DFS traverser that keeps track of 'scopes' + * scope = all parameters that are either bounded by + * two blocking parameters on the same depth level + * or the beginning/end of the outermost group + * + *****************************************************************************/ +class scoped_dfs_traverser +{ +public: + using dfs_traverser = group::depth_first_traverser; + + scoped_dfs_traverser() = default; + + explicit + scoped_dfs_traverser(const group& g): + pos_{g}, lastMatch_{}, posAfterLastMatch_{}, scopes_{}, + ignoreBlocks_{false}, + repeatGroupStarted_{false}, repeatGroupContinues_{false} + {} + + const dfs_traverser& base() const noexcept { return pos_; } + const dfs_traverser& last_match() const noexcept { return lastMatch_; } + + const group& parent() const noexcept { return pos_.parent(); } + + const group* innermost_repeat_group() const noexcept { + return pos_.innermost_repeat_group(); + } + const group* outermost_join_group() const noexcept { + return pos_.outermost_join_group(); + } + const group* innermost_blocking_group() const noexcept { + return pos_.innermost_blocking_group(); + } + const group* innermost_exclusive_group() const noexcept { + return pos_.innermost_exclusive_group(); + } + + const pattern* operator ->() const noexcept { return pos_.operator->(); } + const pattern& operator *() const noexcept { return *pos_; } + + const pattern* ptr() const noexcept { return pos_.operator->(); } + + explicit operator bool() const noexcept { return bool(pos_); } + + bool joinable() const noexcept { return pos_.joinable(); } + arg_string common_flag_prefix() const { return pos_.common_flag_prefix(); } + + void ignore_blocking(bool yes) { ignoreBlocks_ = yes; } + + void invalidate() { + pos_.invalidate(); + } + + bool matched() const noexcept { + return (pos_ == lastMatch_); + } + + bool start_of_repeat_group() const noexcept { return repeatGroupStarted_; } + + //----------------------------------------------------- + scoped_dfs_traverser& + next_sibling() { pos_.next_sibling(); return *this; } + + scoped_dfs_traverser& + next_after_siblings() { pos_.next_after_siblings(); return *this; } + + + //----------------------------------------------------- + scoped_dfs_traverser& + operator ++ () + { + if(!pos_) return *this; + + if(pos_.is_last_in_path()) { + return_to_outermost_scope(); + return *this; + } + + //current pattern can block if it didn't match already + if(ignoreBlocks_ || matched()) { + ++pos_; + } + else if(!pos_->is_group()) { + //current group can block if we didn't have any match in it + const group* g = pos_.outermost_blocking_group_fully_explored(); + //no match in 'g' before -> skip to after its siblings + if(g && !lastMatch_.is_inside(g)) { + pos_.back_to_ancestor(g).next_after_siblings(); + if(!pos_) return_to_outermost_scope(); + } + else if(pos_->blocking()) { + if(pos_.parent().exclusive()) { + pos_.next_sibling(); + } else { + //no match => skip siblings of blocking param + pos_.next_after_siblings(); + } + if(!pos_) return_to_outermost_scope(); + } else { + ++pos_; + } + } else { + ++pos_; + } + check_if_left_scope(); + return *this; + } + + //----------------------------------------------------- + void next_after_match(scoped_dfs_traverser match) + { + if(!match || ignoreBlocks_) return; + + check_repeat_group_start(match); + + lastMatch_ = match.base(); + + // if there is a blocking ancestor -> go back to it + if(!match->blocking()) { + match.pos_.back_to_ancestor(match.innermost_blocking_group()); + } + + //if match is not in current position & current position is blocking + //=> current position has to be advanced by one so that it is + //no longer reachable within current scope + //(can happen for repeatable, blocking parameters) + if(match.base() != pos_ && pos_->blocking()) pos_.next_sibling(); + + if(match->blocking()) { + if(match.pos_.is_alternative()) { + //discard other alternatives + match.pos_.skip_alternatives(); + } + + if(is_last_in_current_scope(match.pos_)) { + //if current param is not repeatable -> back to previous scope + if(!match->repeatable() && !match->is_group()) { + pos_ = std::move(match.pos_); + if(!scopes_.empty()) pos_.undo(scopes_.top()); + } + else { //stay at match position + pos_ = std::move(match.pos_); + } + } + else { //not last in current group + //if current param is not repeatable, go directly to next + if(!match->repeatable() && !match->is_group()) { + ++match.pos_; + } + + if(match.pos_.level() > pos_.level()) { + scopes_.push(pos_.undo_point()); + pos_ = std::move(match.pos_); + } + else if(match.pos_.level() < pos_.level()) { + return_to_level(match.pos_.level()); + } + else { + pos_ = std::move(match.pos_); + } + } + posAfterLastMatch_ = pos_; + } + else { + if(match.pos_.level() < pos_.level()) { + return_to_level(match.pos_.level()); + } + posAfterLastMatch_ = pos_; + } + repeatGroupContinues_ = repeat_group_continues(); + } + +private: + //----------------------------------------------------- + bool is_last_in_current_scope(const dfs_traverser& pos) const + { + if(scopes_.empty()) return pos.is_last_in_path(); + //check if we would leave the current scope on ++ + auto p = pos; + ++p; + return p.level() < scopes_.top().level(); + } + + //----------------------------------------------------- + void check_repeat_group_start(const scoped_dfs_traverser& newMatch) + { + const auto newrg = newMatch.innermost_repeat_group(); + if(!newrg) { + repeatGroupStarted_ = false; + } + else if(lastMatch_.innermost_repeat_group() != newrg) { + repeatGroupStarted_ = true; + } + else if(!repeatGroupContinues_ || !newMatch.repeatGroupContinues_) { + repeatGroupStarted_ = true; + } + else { + //special case: repeat group is outermost group + //=> we can never really 'leave' and 'reenter' it + //but if the current scope is the first element, then we are + //conceptually at a position 'before' the group + repeatGroupStarted_ = scopes_.empty() || ( + newrg == pos_.root() && + scopes_.top().param() == &(*pos_.root()->begin()) ); + } + repeatGroupContinues_ = repeatGroupStarted_; + } + + //----------------------------------------------------- + bool repeat_group_continues() const + { + if(!repeatGroupContinues_) return false; + const auto curRepGroup = pos_.innermost_repeat_group(); + if(!curRepGroup) return false; + if(curRepGroup != lastMatch_.innermost_repeat_group()) return false; + if(!posAfterLastMatch_) return false; + return true; + } + + //----------------------------------------------------- + void check_if_left_scope() + { + if(posAfterLastMatch_) { + if(pos_.level() < posAfterLastMatch_.level()) { + while(!scopes_.empty() && scopes_.top().level() >= pos_.level()) { + pos_.undo(scopes_.top()); + scopes_.pop(); + } + posAfterLastMatch_.invalidate(); + } + } + while(!scopes_.empty() && scopes_.top().level() > pos_.level()) { + pos_.undo(scopes_.top()); + scopes_.pop(); + } + repeatGroupContinues_ = repeat_group_continues(); + } + + //----------------------------------------------------- + void return_to_outermost_scope() + { + posAfterLastMatch_.invalidate(); + + if(scopes_.empty()) { + pos_.invalidate(); + repeatGroupContinues_ = false; + return; + } + + while(!scopes_.empty() && (!pos_ || pos_.level() >= 1)) { + pos_.undo(scopes_.top()); + scopes_.pop(); + } + while(!scopes_.empty()) scopes_.pop(); + + repeatGroupContinues_ = repeat_group_continues(); + } + + //----------------------------------------------------- + void return_to_level(int level) + { + if(pos_.level() <= level) return; + while(!scopes_.empty() && pos_.level() > level) { + pos_.undo(scopes_.top()); + scopes_.pop(); + } + }; + + dfs_traverser pos_; + dfs_traverser lastMatch_; + dfs_traverser posAfterLastMatch_; + std::stack scopes_; + bool ignoreBlocks_ = false; + bool repeatGroupStarted_ = false; + bool repeatGroupContinues_ = false; +}; + + + + +/***************************************************************************** + * + * some parameter property predicates + * + *****************************************************************************/ +struct select_all { + bool operator () (const parameter&) const noexcept { return true; } +}; + +struct select_flags { + bool operator () (const parameter& p) const noexcept { + return !p.flags().empty(); + } +}; + +struct select_values { + bool operator () (const parameter& p) const noexcept { + return p.flags().empty(); + } +}; + + + +/*************************************************************************//** + * + * @brief result of a matching operation + * + *****************************************************************************/ +class match_t { +public: + using size_type = arg_string::size_type; + + match_t() = default; + + match_t(arg_string s, scoped_dfs_traverser p): + str_{std::move(s)}, pos_{std::move(p)} + {} + + size_type length() const noexcept { return str_.size(); } + + const arg_string& str() const noexcept { return str_; } + const scoped_dfs_traverser& pos() const noexcept { return pos_; } + + explicit operator bool() const noexcept { return bool(pos_); } + +private: + arg_string str_; + scoped_dfs_traverser pos_; +}; + + + +/*************************************************************************//** + * + * @brief finds the first parameter that matches a given string; + * candidate parameters are traversed using a scoped DFS traverser + * + *****************************************************************************/ +template +match_t +full_match(scoped_dfs_traverser pos, const arg_string& arg, + const ParamSelector& select) +{ + while(pos) { + if(pos->is_param()) { + const auto& param = pos->as_param(); + if(select(param)) { + const auto match = param.match(arg); + if(match && match.length() == arg.size()) { + return match_t{arg, std::move(pos)}; + } + } + } + ++pos; + } + return match_t{}; +} + + + +/*************************************************************************//** + * + * @brief finds the first parameter that matches any (non-empty) prefix + * of a given string; + * candidate parameters are traversed using a scoped DFS traverser + * + *****************************************************************************/ +template +match_t +longest_prefix_match(scoped_dfs_traverser pos, const arg_string& arg, + const ParamSelector& select) +{ + match_t longest; + + while(pos) { + if(pos->is_param()) { + const auto& param = pos->as_param(); + if(select(param)) { + auto match = param.match(arg); + if(match.prefix()) { + if(match.length() == arg.size()) { + return match_t{arg, std::move(pos)}; + } + else if(match.length() > longest.length()) { + longest = match_t{arg.substr(match.at(), match.length()), + pos}; + } + } + } + } + ++pos; + } + return longest; +} + + + +/*************************************************************************//** + * + * @brief finds the first parameter that partially matches a given string; + * candidate parameters are traversed using a scoped DFS traverser + * + *****************************************************************************/ +template +match_t +partial_match(scoped_dfs_traverser pos, const arg_string& arg, + const ParamSelector& select) +{ + while(pos) { + if(pos->is_param()) { + const auto& param = pos->as_param(); + if(select(param)) { + const auto match = param.match(arg); + if(match) { + return match_t{arg.substr(match.at(), match.length()), + std::move(pos)}; + } + } + } + ++pos; + } + return match_t{}; +} + +} //namespace detail + + + + + + +/***************************************************************//** + * + * @brief default command line arguments parser + * + *******************************************************************/ +class parser +{ +public: + using dfs_traverser = group::depth_first_traverser; + using scoped_dfs_traverser = detail::scoped_dfs_traverser; + + + /*****************************************************//** + * @brief arg -> parameter mapping + *********************************************************/ + class arg_mapping { + public: + friend class parser; + + explicit + arg_mapping(arg_index idx, arg_string s, + const dfs_traverser& match) + : + index_{idx}, arg_{std::move(s)}, match_{match}, + repeat_{0}, startsRepeatGroup_{false}, + blocked_{false}, conflict_{false} + {} + + explicit + arg_mapping(arg_index idx, arg_string s) : + index_{idx}, arg_{std::move(s)}, match_{}, + repeat_{0}, startsRepeatGroup_{false}, + blocked_{false}, conflict_{false} + {} + + arg_index index() const noexcept { return index_; } + const arg_string& arg() const noexcept { return arg_; } + + const parameter* param() const noexcept { + return match_ && match_->is_param() + ? &(match_->as_param()) : nullptr; + } + + std::size_t repeat() const noexcept { return repeat_; } + + bool blocked() const noexcept { return blocked_; } + bool conflict() const noexcept { return conflict_; } + + bool bad_repeat() const noexcept { + if(!param()) return false; + return repeat_ > 0 && !param()->repeatable() + && !match_.innermost_repeat_group(); + } + + bool any_error() const noexcept { + return !match_ || blocked() || conflict() || bad_repeat(); + } + + private: + arg_index index_; + arg_string arg_; + dfs_traverser match_; + std::size_t repeat_; + bool startsRepeatGroup_; + bool blocked_; + bool conflict_; + }; + + /*****************************************************//** + * @brief references a non-matched, required parameter + *********************************************************/ + class missing_event { + public: + explicit + missing_event(const parameter* p, arg_index after): + param_{p}, aftIndex_{after} + {} + + const parameter* param() const noexcept { return param_; } + + arg_index after_index() const noexcept { return aftIndex_; } + + private: + const parameter* param_; + arg_index aftIndex_; + }; + + //----------------------------------------------------- + using missing_events = std::vector; + using arg_mappings = std::vector; + + +private: + struct miss_candidate { + miss_candidate(dfs_traverser p, arg_index idx, + bool firstInRepeatGroup = false): + pos{std::move(p)}, index{idx}, + startsRepeatGroup{firstInRepeatGroup} + {} + + dfs_traverser pos; + arg_index index; + bool startsRepeatGroup; + }; + using miss_candidates = std::vector; + + +public: + //--------------------------------------------------------------- + /** @brief initializes parser with a command line interface + * @param offset = argument index offset used for reports + * */ + explicit + parser(const group& root, arg_index offset = 0): + root_{&root}, pos_{root}, + index_{offset-1}, eaten_{0}, + args_{}, missCand_{}, blocked_{false} + { + for_each_potential_miss(dfs_traverser{root}, + [this](const dfs_traverser& p){ + missCand_.emplace_back(p, index_); + }); + } + + + //--------------------------------------------------------------- + /** @brief processes one command line argument */ + bool operator() (const arg_string& arg) + { + ++eaten_; + ++index_; + + if(!valid()) return false; + + if(!blocked_ && try_match(arg)) return true; + + if(try_match_blocked(arg)) return false; + + //skipping of blocking & required patterns is not allowed + if(!blocked_ && !pos_.matched() && pos_->required() && pos_->blocking()) { + blocked_ = true; + } + + add_nomatch(arg); + return false; + } + + + //--------------------------------------------------------------- + /** @brief returns range of argument -> parameter mappings */ + const arg_mappings& args() const { + return args_; + } + + /** @brief returns list of missing events */ + missing_events missed() const { + missing_events misses; + misses.reserve(missCand_.size()); + for(auto i = missCand_.begin(); i != missCand_.end(); ++i) { + misses.emplace_back(&(i->pos->as_param()), i->index); + } + return misses; + } + + /** @brief returns number of processed command line arguments */ + arg_index parse_count() const noexcept { return eaten_; } + + /** @brief returns false if previously processed command line arguments + * lead to an invalid / inconsistent parsing result + */ + bool valid() const noexcept { return bool(pos_); } + + /** @brief returns false if previously processed command line arguments + * lead to an invalid / inconsistent parsing result + */ + explicit operator bool() const noexcept { return valid(); } + + +private: + //--------------------------------------------------------------- + using match_t = detail::match_t; + + + //--------------------------------------------------------------- + /** @brief try to match argument with unreachable parameter */ + bool try_match_blocked(const arg_string& arg) + { + //try to match ahead (using temporary parser) + if(pos_) { + auto ahead = *this; + if(try_match_blocked(std::move(ahead), arg)) return true; + } + + //try to match from the beginning (using temporary parser) + if(root_) { + parser all{*root_, index_+1}; + if(try_match_blocked(std::move(all), arg)) return true; + } + + return false; + } + + //--------------------------------------------------------------- + bool try_match_blocked(parser&& parse, const arg_string& arg) + { + const auto nold = int(parse.args_.size()); + + parse.pos_.ignore_blocking(true); + + if(!parse.try_match(arg)) return false; + + for(auto i = parse.args_.begin() + nold; i != parse.args_.end(); ++i) { + args_.push_back(*i); + args_.back().blocked_ = true; + } + return true; + } + + //--------------------------------------------------------------- + /** @brief try to find a parameter/pattern that matches 'arg' */ + bool try_match(const arg_string& arg) + { + //match greedy parameters before everything else + if(pos_->is_param() && pos_->blocking() && pos_->as_param().greedy()) { + const auto match = pos_->as_param().match(arg); + if(match && match.length() == arg.size()) { + add_match(detail::match_t{arg,pos_}); + return true; + } + } + + //try flags first (alone, joinable or strict sequence) + if(try_match_full(arg, detail::select_flags{})) return true; + if(try_match_joined_flags(arg)) return true; + if(try_match_joined_sequence(arg, detail::select_flags{})) return true; + //try value params (alone or strict sequence) + if(try_match_full(arg, detail::select_values{})) return true; + if(try_match_joined_sequence(arg, detail::select_all{})) return true; + //try joinable params + values in any order + if(try_match_joined_params(arg)) return true; + return false; + } + + //--------------------------------------------------------------- + /** + * @brief try to match full argument + * @param select : predicate that candidate parameters must satisfy + */ + template + bool try_match_full(const arg_string& arg, const ParamSelector& select) + { + auto match = detail::full_match(pos_, arg, select); + if(!match) return false; + add_match(match); + return true; + } + + //--------------------------------------------------------------- + /** + * @brief try to match argument as blocking sequence of parameters + * @param select : predicate that a parameter matching the prefix of + * 'arg' must satisfy + */ + template + bool try_match_joined_sequence(arg_string arg, + const ParamSelector& acceptFirst) + { + auto fstMatch = detail::longest_prefix_match(pos_, arg, acceptFirst); + + if(!fstMatch) return false; + + if(fstMatch.str().size() == arg.size()) { + add_match(fstMatch); + return true; + } + + if(!fstMatch.pos()->blocking()) return false; + + auto pos = fstMatch.pos(); + pos.ignore_blocking(true); + const auto parent = &pos.parent(); + if(!pos->repeatable()) ++pos; + + arg.erase(0, fstMatch.str().size()); + std::vector matches { std::move(fstMatch) }; + + while(!arg.empty() && pos && + pos->blocking() && pos->is_param() && + (&pos.parent() == parent)) + { + auto match = pos->as_param().match(arg); + + if(match.prefix()) { + matches.emplace_back(arg.substr(0,match.length()), pos); + arg.erase(0, match.length()); + if(!pos->repeatable()) ++pos; + } + else { + if(!pos->repeatable()) return false; + ++pos; + } + + } + //if arg not fully covered => discard temporary matches + if(!arg.empty() || matches.empty()) return false; + + for(const auto& m : matches) add_match(m); + return true; + } + + //----------------------------------------------------- + /** @brief try to match 'arg' as a concatenation of joinable flags */ + bool try_match_joined_flags(const arg_string& arg) + { + return find_join_group(pos_, [&](const group& g) { + return try_match_joined(g, arg, detail::select_flags{}, + g.common_flag_prefix()); + }); + } + + //--------------------------------------------------------------- + /** @brief try to match 'arg' as a concatenation of joinable parameters */ + bool try_match_joined_params(const arg_string& arg) + { + return find_join_group(pos_, [&](const group& g) { + return try_match_joined(g, arg, detail::select_all{}); + }); + } + + //----------------------------------------------------- + /** @brief try to match 'arg' as concatenation of joinable parameters + * that are all contained within one group + */ + template + bool try_match_joined(const group& joinGroup, arg_string arg, + const ParamSelector& select, + const arg_string& prefix = "") + { + //temporary parser with 'joinGroup' as top-level group + parser parse {joinGroup}; + //records temporary matches + std::vector matches; + + while(!arg.empty()) { + auto match = detail::longest_prefix_match(parse.pos_, arg, select); + + if(!match) return false; + + arg.erase(0, match.str().size()); + //make sure prefix is always present after the first match + //so that, e.g., flags "-a" and "-b" will be found in "-ab" + if(!arg.empty() && !prefix.empty() && arg.find(prefix) != 0 && + prefix != match.str()) + { + arg.insert(0,prefix); + } + + parse.add_match(match); + matches.push_back(std::move(match)); + } + + if(!arg.empty() || matches.empty()) return false; + + if(!parse.missCand_.empty()) return false; + for(const auto& a : parse.args_) if(a.any_error()) return false; + + //replay matches onto *this + for(const auto& m : matches) add_match(m); + return true; + } + + //----------------------------------------------------- + template + bool find_join_group(const scoped_dfs_traverser& start, + const GroupSelector& accept) const + { + if(start && start.parent().joinable()) { + const auto& g = start.parent(); + if(accept(g)) return true; + return false; + } + + auto pos = start; + while(pos) { + if(pos->is_group() && pos->as_group().joinable()) { + const auto& g = pos->as_group(); + if(accept(g)) return true; + pos.next_sibling(); + } + else { + ++pos; + } + } + return false; + } + + + //--------------------------------------------------------------- + void add_nomatch(const arg_string& arg) { + args_.emplace_back(index_, arg); + } + + + //--------------------------------------------------------------- + void add_match(const match_t& match) + { + const auto& pos = match.pos(); + if(!pos || !pos->is_param()) return; + + pos_.next_after_match(pos); + + arg_mapping newArg{index_, match.str(), pos.base()}; + newArg.repeat_ = occurrences_of(&pos->as_param()); + newArg.conflict_ = check_conflicts(pos.base()); + newArg.startsRepeatGroup_ = pos_.start_of_repeat_group(); + args_.push_back(std::move(newArg)); + + add_miss_candidates_after(pos); + clean_miss_candidates_for(pos.base()); + discard_alternative_miss_candidates(pos.base()); + + } + + //----------------------------------------------------- + bool check_conflicts(const dfs_traverser& match) + { + if(pos_.start_of_repeat_group()) return false; + bool conflict = false; + for(const auto& m : match.stack()) { + if(m.parent->exclusive()) { + for(auto i = args_.rbegin(); i != args_.rend(); ++i) { + if(!i->blocked()) { + for(const auto& c : i->match_.stack()) { + //sibling within same exclusive group => conflict + if(c.parent == m.parent && c.cur != m.cur) { + conflict = true; + i->conflict_ = true; + } + } + } + //check for conflicts only within current repeat cycle + if(i->startsRepeatGroup_) break; + } + } + } + return conflict; + } + + //----------------------------------------------------- + void clean_miss_candidates_for(const dfs_traverser& match) + { + auto i = std::find_if(missCand_.rbegin(), missCand_.rend(), + [&](const miss_candidate& m) { + return &(*m.pos) == &(*match); + }); + + if(i != missCand_.rend()) { + missCand_.erase(prev(i.base())); + } + } + + //----------------------------------------------------- + void discard_alternative_miss_candidates(const dfs_traverser& match) + { + if(missCand_.empty()) return; + //find out, if miss candidate is sibling of one of the same + //alternative groups that the current match is a member of + //if so, we can discard the miss + + //go through all exclusive groups of matching pattern + for(const auto& m : match.stack()) { + if(m.parent->exclusive()) { + for(auto i = int(missCand_.size())-1; i >= 0; --i) { + bool removed = false; + for(const auto& c : missCand_[i].pos.stack()) { + //sibling within same exclusive group => discard + if(c.parent == m.parent && c.cur != m.cur) { + missCand_.erase(missCand_.begin() + i); + if(missCand_.empty()) return; + removed = true; + break; + } + } + //remove miss candidates only within current repeat cycle + if(i > 0 && removed) { + if(missCand_[i-1].startsRepeatGroup) break; + } else { + if(missCand_[i].startsRepeatGroup) break; + } + } + } + } + } + + //----------------------------------------------------- + void add_miss_candidates_after(const scoped_dfs_traverser& match) + { + auto npos = match.base(); + if(npos.is_alternative()) npos.skip_alternatives(); + ++npos; + //need to add potential misses if: + //either new repeat group was started + const auto newRepGroup = match.innermost_repeat_group(); + if(newRepGroup) { + if(pos_.start_of_repeat_group()) { + for_each_potential_miss(std::move(npos), + [&,this](const dfs_traverser& pos) { + //only add candidates within repeat group + if(newRepGroup == pos.innermost_repeat_group()) { + missCand_.emplace_back(pos, index_, true); + } + }); + } + } + //... or an optional blocking param was hit + else if(match->blocking() && !match->required() && + npos.level() >= match.base().level()) + { + for_each_potential_miss(std::move(npos), + [&,this](const dfs_traverser& pos) { + //only add new candidates + if(std::find_if(missCand_.begin(), missCand_.end(), + [&](const miss_candidate& c){ + return &(*c.pos) == &(*pos); + }) == missCand_.end()) + { + missCand_.emplace_back(pos, index_); + } + }); + } + + } + + //----------------------------------------------------- + template + static void + for_each_potential_miss(dfs_traverser pos, Action&& action) + { + const auto level = pos.level(); + while(pos && pos.level() >= level) { + if(pos->is_group() ) { + const auto& g = pos->as_group(); + if(g.all_optional() || (g.exclusive() && g.any_optional())) { + pos.next_sibling(); + } else { + ++pos; + } + } else { //param + if(pos->required()) { + action(pos); + ++pos; + } else if(pos->blocking()) { //optional + blocking + pos.next_after_siblings(); + } else { + ++pos; + } + } + } + } + + + //--------------------------------------------------------------- + std::size_t occurrences_of(const parameter* p) const + { + if(!p) return 0; + + auto i = std::find_if(args_.rbegin(), args_.rend(), + [p](const arg_mapping& a){ return a.param() == p; }); + + if(i != args_.rend()) return i->repeat() + 1; + return 0; + } + + + //--------------------------------------------------------------- + const group* root_; + scoped_dfs_traverser pos_; + arg_index index_; + arg_index eaten_; + arg_mappings args_; + miss_candidates missCand_; + bool blocked_; +}; + + + + +/*************************************************************************//** + * + * @brief contains argument -> parameter mappings + * and missing parameters + * + *****************************************************************************/ +class parsing_result +{ +public: + using arg_mapping = parser::arg_mapping; + using arg_mappings = parser::arg_mappings; + using missing_event = parser::missing_event; + using missing_events = parser::missing_events; + using iterator = arg_mappings::const_iterator; + + //----------------------------------------------------- + /** @brief default: empty result */ + parsing_result() = default; + + parsing_result(arg_mappings arg2param, missing_events misses): + arg2param_{std::move(arg2param)}, missing_{std::move(misses)} + {} + + //----------------------------------------------------- + /** @brief returns number of arguments that could not be mapped to + * a parameter + */ + arg_mappings::size_type + unmapped_args_count() const noexcept { + return std::count_if(arg2param_.begin(), arg2param_.end(), + [](const arg_mapping& a){ return !a.param(); }); + } + + /** @brief returns if any argument could only be matched by an + * unreachable parameter + */ + bool any_blocked() const noexcept { + return std::any_of(arg2param_.begin(), arg2param_.end(), + [](const arg_mapping& a){ return a.blocked(); }); + } + + /** @brief returns if any argument matched more than one parameter + * that were mutually exclusive */ + bool any_conflict() const noexcept { + return std::any_of(arg2param_.begin(), arg2param_.end(), + [](const arg_mapping& a){ return a.conflict(); }); + } + + /** @brief returns if any parameter matched repeatedly although + * it was not allowed to */ + bool any_bad_repeat() const noexcept { + return std::any_of(arg2param_.begin(), arg2param_.end(), + [](const arg_mapping& a){ return a.bad_repeat(); }); + } + + /** @brief returns true if any parsing error / violation of the + * command line interface definition occurred */ + bool any_error() const noexcept { + return unmapped_args_count() > 0 || !missing().empty() || + any_blocked() || any_conflict() || any_bad_repeat(); + } + + /** @brief returns true if no parsing error / violation of the + * command line interface definition occurred */ + explicit operator bool() const noexcept { return !any_error(); } + + /** @brief access to range of missing parameter match events */ + const missing_events& missing() const noexcept { return missing_; } + + /** @brief returns non-mutating iterator to position of + * first argument -> parameter mapping */ + iterator begin() const noexcept { return arg2param_.begin(); } + /** @brief returns non-mutating iterator to position one past the + * last argument -> parameter mapping */ + iterator end() const noexcept { return arg2param_.end(); } + +private: + //----------------------------------------------------- + arg_mappings arg2param_; + missing_events missing_; +}; + + + + +namespace detail { +namespace { + +/*************************************************************************//** + * + * @brief correct some common problems + * does not - and MUST NOT - change the number of arguments + * (no insertions or deletions allowed) + * + *****************************************************************************/ +void sanitize_args(arg_list& args) +{ + //e.g. {"-o12", ".34"} -> {"-o", "12.34"} + + if(args.empty()) return; + + for(auto i = begin(args)+1; i != end(args); ++i) { + if(i != begin(args) && i->size() > 1 && + i->find('.') == 0 && std::isdigit((*i)[1]) ) + { + //find trailing digits in previous arg + using std::prev; + auto& prv = *prev(i); + auto fstDigit = std::find_if_not(prv.rbegin(), prv.rend(), + [](arg_string::value_type c){ + return std::isdigit(c); + }).base(); + + //handle leading sign + if(fstDigit > prv.begin() && + (*prev(fstDigit) == '+' || *prev(fstDigit) == '-')) + { + --fstDigit; + } + + //prepend digits from previous arg + i->insert(begin(*i), fstDigit, end(prv)); + + //erase digits in previous arg + prv.erase(fstDigit, end(prv)); + } + } +} + + + +/*************************************************************************//** + * + * @brief executes actions based on a parsing result + * + *****************************************************************************/ +void execute_actions(const parsing_result& res) +{ + for(const auto& m : res) { + if(m.param()) { + const auto& param = *(m.param()); + + if(m.repeat() > 0) param.notify_repeated(m.index()); + if(m.blocked()) param.notify_blocked(m.index()); + if(m.conflict()) param.notify_conflict(m.index()); + //main action + if(!m.any_error()) param.execute_actions(m.arg()); + } + } + + for(auto m : res.missing()) { + if(m.param()) m.param()->notify_missing(m.after_index()); + } +} + + + +/*************************************************************************//** + * + * @brief parses input args + * + *****************************************************************************/ +static parsing_result +parse_args(const arg_list& args, const group& cli, + arg_index offset = 0) +{ + //parse args and store unrecognized arg indices + parser parse{cli, offset}; + for(const auto& arg : args) { + parse(arg); + if(!parse.valid()) break; + } + + return parsing_result{parse.args(), parse.missed()}; +} + +/*************************************************************************//** + * + * @brief parses input args & executes actions + * + *****************************************************************************/ +static parsing_result +parse_and_execute(const arg_list& args, const group& cli, + arg_index offset = 0) +{ + auto result = parse_args(args, cli, offset); + + execute_actions(result); + + return result; +} + +} //anonymous namespace +} // namespace detail + + + + +/*************************************************************************//** + * + * @brief parses vector of arg strings and executes actions + * + *****************************************************************************/ +inline parsing_result +parse(arg_list args, const group& cli) +{ + detail::sanitize_args(args); + return detail::parse_and_execute(args, cli); +} + + +/*************************************************************************//** + * + * @brief parses initializer_list of C-style arg strings and executes actions + * + *****************************************************************************/ +inline parsing_result +parse(std::initializer_list arglist, const group& cli) +{ + arg_list args; + args.reserve(arglist.size()); + for(auto a : arglist) { + args.push_back(a); + } + + return parse(std::move(args), cli); +} + + +/*************************************************************************//** + * + * @brief parses range of arg strings and executes actions + * + *****************************************************************************/ +template +inline parsing_result +parse(InputIterator first, InputIterator last, const group& cli) +{ + return parse(arg_list(first,last), cli); +} + + +/*************************************************************************//** + * + * @brief parses the standard array of command line arguments; omits argv[0] + * + *****************************************************************************/ +inline parsing_result +parse(const int argc, char* argv[], const group& cli, arg_index offset = 1) +{ + arg_list args; + if(offset < argc) args.assign(argv+offset, argv+argc); + detail::sanitize_args(args); + return detail::parse_and_execute(args, cli, offset); +} + + + + + + +/*************************************************************************//** + * + * @brief filter predicate for parameters and groups; + * Can be used to limit documentation generation to parameter subsets. + * + *****************************************************************************/ +class param_filter +{ +public: + /** @brief only allow parameters with given prefix */ + param_filter& prefix(const arg_string& p) noexcept { + prefix_ = p; return *this; + } + /** @brief only allow parameters with given prefix */ + param_filter& prefix(arg_string&& p) noexcept { + prefix_ = std::move(p); return *this; + } + const arg_string& prefix() const noexcept { return prefix_; } + + /** @brief only allow parameters with given requirement status */ + param_filter& required(tri t) noexcept { required_ = t; return *this; } + tri required() const noexcept { return required_; } + + /** @brief only allow parameters with given blocking status */ + param_filter& blocking(tri t) noexcept { blocking_ = t; return *this; } + tri blocking() const noexcept { return blocking_; } + + /** @brief only allow parameters with given repeatable status */ + param_filter& repeatable(tri t) noexcept { repeatable_ = t; return *this; } + tri repeatable() const noexcept { return repeatable_; } + + /** @brief only allow parameters with given docstring status */ + param_filter& has_doc(tri t) noexcept { hasDoc_ = t; return *this; } + tri has_doc() const noexcept { return hasDoc_; } + + + /** @brief returns true, if parameter satisfies all filters */ + bool operator() (const parameter& p) const noexcept { + if(!prefix_.empty()) { + if(!std::any_of(p.flags().begin(), p.flags().end(), + [&](const arg_string& flag){ + return str::has_prefix(flag, prefix_); + })) return false; + } + if(required() != p.required()) return false; + if(blocking() != p.blocking()) return false; + if(repeatable() != p.repeatable()) return false; + if(has_doc() != !p.doc().empty()) return false; + return true; + } + +private: + arg_string prefix_; + tri required_ = tri::either; + tri blocking_ = tri::either; + tri repeatable_ = tri::either; + tri hasDoc_ = tri::yes; +}; + + + + + + +/*************************************************************************//** + * + * @brief documentation formatting options + * + *****************************************************************************/ +class doc_formatting +{ +public: + using string = doc_string; + + /** @brief same as 'first_column' */ +#if __cplusplus >= 201402L + [[deprecated]] +#endif + doc_formatting& start_column(int col) { return first_column(col); } +#if __cplusplus >= 201402L + [[deprecated]] +#endif + int start_column() const noexcept { return first_column(); } + + /** @brief determines column where documentation printing starts */ + doc_formatting& + first_column(int col) { + //limit to [0,last_column] but push doc_column to the right if necessary + if(col < 0) col = 0; + else if(col > last_column()) col = last_column(); + if(col > doc_column()) doc_column(first_column()); + firstCol_ = col; + return *this; + } + int first_column() const noexcept { + return firstCol_; + } + + /** @brief determines column where docstrings start */ + doc_formatting& + doc_column(int col) { + //limit to [first_column,last_column] + if(col < 0) col = 0; + else if(col < first_column()) col = first_column(); + else if(col > last_column()) col = last_column(); + docCol_ = col; + return *this; + } + int doc_column() const noexcept { + return docCol_; + } + + /** @brief determines column that no documentation text must exceed; + * (text should be wrapped appropriately after this column) + */ + doc_formatting& + last_column(int col) { + //limit to [first_column,oo] but push doc_column to the left if necessary + if(col < first_column()) col = first_column(); + if(col < doc_column()) doc_column(col); + lastCol_ = col; + return *this; + } + + int last_column() const noexcept { + return lastCol_; + } + + /** @brief determines indent of documentation lines + * for children of a documented group */ + doc_formatting& indent_size(int indent) { indentSize_ = indent; return *this; } + int indent_size() const noexcept { return indentSize_; } + + /** @brief determines string to be used + * if a parameter has no flags and no label */ + doc_formatting& empty_label(const string& label) { + emptyLabel_ = label; + return *this; + } + const string& empty_label() const noexcept { return emptyLabel_; } + + /** @brief determines string for separating parameters */ + doc_formatting& param_separator(const string& sep) { + paramSep_ = sep; + return *this; + } + const string& param_separator() const noexcept { return paramSep_; } + + /** @brief determines string for separating groups (in usage lines) */ + doc_formatting& group_separator(const string& sep) { + groupSep_ = sep; + return *this; + } + const string& group_separator() const noexcept { return groupSep_; } + + /** @brief determines string for separating alternative parameters */ + doc_formatting& alternative_param_separator(const string& sep) { + altParamSep_ = sep; + return *this; + } + const string& alternative_param_separator() const noexcept { return altParamSep_; } + + /** @brief determines string for separating alternative groups */ + doc_formatting& alternative_group_separator(const string& sep) { + altGroupSep_ = sep; + return *this; + } + const string& alternative_group_separator() const noexcept { return altGroupSep_; } + + /** @brief determines string for separating flags of the same parameter */ + doc_formatting& flag_separator(const string& sep) { + flagSep_ = sep; + return *this; + } + const string& flag_separator() const noexcept { return flagSep_; } + + /** @brief determines strings surrounding parameter labels */ + doc_formatting& + surround_labels(const string& prefix, const string& postfix) { + labelPre_ = prefix; + labelPst_ = postfix; + return *this; + } + const string& label_prefix() const noexcept { return labelPre_; } + const string& label_postfix() const noexcept { return labelPst_; } + + /** @brief determines strings surrounding optional parameters/groups */ + doc_formatting& + surround_optional(const string& prefix, const string& postfix) { + optionPre_ = prefix; + optionPst_ = postfix; + return *this; + } + const string& optional_prefix() const noexcept { return optionPre_; } + const string& optional_postfix() const noexcept { return optionPst_; } + + /** @brief determines strings surrounding repeatable parameters/groups */ + doc_formatting& + surround_repeat(const string& prefix, const string& postfix) { + repeatPre_ = prefix; + repeatPst_ = postfix; + return *this; + } + const string& repeat_prefix() const noexcept { return repeatPre_; } + const string& repeat_postfix() const noexcept { return repeatPst_; } + + /** @brief determines strings surrounding exclusive groups */ + doc_formatting& + surround_alternatives(const string& prefix, const string& postfix) { + alternPre_ = prefix; + alternPst_ = postfix; + return *this; + } + const string& alternatives_prefix() const noexcept { return alternPre_; } + const string& alternatives_postfix() const noexcept { return alternPst_; } + + /** @brief determines strings surrounding alternative flags */ + doc_formatting& + surround_alternative_flags(const string& prefix, const string& postfix) { + alternFlagPre_ = prefix; + alternFlagPst_ = postfix; + return *this; + } + const string& alternative_flags_prefix() const noexcept { return alternFlagPre_; } + const string& alternative_flags_postfix() const noexcept { return alternFlagPst_; } + + /** @brief determines strings surrounding non-exclusive groups */ + doc_formatting& + surround_group(const string& prefix, const string& postfix) { + groupPre_ = prefix; + groupPst_ = postfix; + return *this; + } + const string& group_prefix() const noexcept { return groupPre_; } + const string& group_postfix() const noexcept { return groupPst_; } + + /** @brief determines strings surrounding joinable groups */ + doc_formatting& + surround_joinable(const string& prefix, const string& postfix) { + joinablePre_ = prefix; + joinablePst_ = postfix; + return *this; + } + const string& joinable_prefix() const noexcept { return joinablePre_; } + const string& joinable_postfix() const noexcept { return joinablePst_; } + + /** @brief determines maximum number of flags per parameter to be printed + * in detailed parameter documentation lines */ + doc_formatting& max_flags_per_param_in_doc(int max) { + maxAltInDocs_ = max > 0 ? max : 0; + return *this; + } + int max_flags_per_param_in_doc() const noexcept { return maxAltInDocs_; } + + /** @brief determines maximum number of flags per parameter to be printed + * in usage lines */ + doc_formatting& max_flags_per_param_in_usage(int max) { + maxAltInUsage_ = max > 0 ? max : 0; + return *this; + } + int max_flags_per_param_in_usage() const noexcept { return maxAltInUsage_; } + + /** @brief determines number of empty rows after one single-line + * documentation entry */ + doc_formatting& line_spacing(int lines) { + lineSpc_ = lines > 0 ? lines : 0; + return *this; + } + int line_spacing() const noexcept { return lineSpc_; } + + /** @brief determines number of empty rows before and after a paragraph; + * a paragraph is defined by a documented group or if + * a parameter documentation entry used more than one line */ + doc_formatting& paragraph_spacing(int lines) { + paragraphSpc_ = lines > 0 ? lines : 0; + return *this; + } + int paragraph_spacing() const noexcept { return paragraphSpc_; } + + /** @brief determines if alternative flags with a common prefix should + * be printed in a merged fashion */ + doc_formatting& merge_alternative_flags_with_common_prefix(bool yes = true) { + mergeAltCommonPfx_ = yes; + return *this; + } + bool merge_alternative_flags_with_common_prefix() const noexcept { + return mergeAltCommonPfx_; + } + + /** @brief determines if joinable flags with a common prefix should + * be printed in a merged fashion */ + doc_formatting& merge_joinable_with_common_prefix(bool yes = true) { + mergeJoinableCommonPfx_ = yes; + return *this; + } + bool merge_joinable_with_common_prefix() const noexcept { + return mergeJoinableCommonPfx_; + } + + /** @brief determines if children of exclusive groups should be printed + * on individual lines if the exceed 'alternatives_min_split_size' + */ + doc_formatting& split_alternatives(bool yes = true) { + splitTopAlt_ = yes; + return *this; + } + bool split_alternatives() const noexcept { + return splitTopAlt_; + } + + /** @brief determines how many children exclusive groups can have before + * their children are printed on individual usage lines */ + doc_formatting& alternatives_min_split_size(int size) { + groupSplitSize_ = size > 0 ? size : 0; + return *this; + } + int alternatives_min_split_size() const noexcept { return groupSplitSize_; } + + /** @brief determines whether to ignore new line characters in docstrings + */ + doc_formatting& ignore_newline_chars(bool yes = true) { + ignoreNewlines_ = yes; + return *this; + } + bool ignore_newline_chars() const noexcept { + return ignoreNewlines_; + } + +private: + string paramSep_ = string(" "); + string groupSep_ = string(" "); + string altParamSep_ = string("|"); + string altGroupSep_ = string(" | "); + string flagSep_ = string(", "); + string labelPre_ = string("<"); + string labelPst_ = string(">"); + string optionPre_ = string("["); + string optionPst_ = string("]"); + string repeatPre_ = string(""); + string repeatPst_ = string("..."); + string groupPre_ = string("("); + string groupPst_ = string(")"); + string alternPre_ = string("("); + string alternPst_ = string(")"); + string alternFlagPre_ = string(""); + string alternFlagPst_ = string(""); + string joinablePre_ = string("("); + string joinablePst_ = string(")"); + string emptyLabel_ = string(""); + int firstCol_ = 8; + int docCol_ = 20; + int lastCol_ = 100; + int indentSize_ = 4; + int maxAltInUsage_ = 1; + int maxAltInDocs_ = 32; + int lineSpc_ = 0; + int paragraphSpc_ = 1; + int groupSplitSize_ = 3; + bool splitTopAlt_ = true; + bool mergeAltCommonPfx_ = false; + bool mergeJoinableCommonPfx_ = true; + bool ignoreNewlines_ = false; +}; + + + +namespace detail { + +/*************************************************************************//** + * + * @brief stream decorator + * that applies formatting like line wrapping + * + *****************************************************************************/ +template +class formatting_ostream +{ +public: + using string_type = StringT; + using size_type = typename string_type::size_type; + using char_type = typename string_type::value_type; + + formatting_ostream(OStream& os): + os_(os), + curCol_{0}, firstCol_{0}, lastCol_{100}, + hangingIndent_{0}, paragraphSpacing_{0}, paragraphSpacingThreshold_{2}, + curBlankLines_{0}, curParagraphLines_{1}, + totalNonBlankLines_{0}, + ignoreInputNls_{false} + {} + + + //--------------------------------------------------------------- + const OStream& base() const noexcept { return os_; } + OStream& base() noexcept { return os_; } + + bool good() const { return os_.good(); } + + + //--------------------------------------------------------------- + /** @brief determines the leftmost border of the text body */ + formatting_ostream& first_column(int c) { + firstCol_ = c < 0 ? 0 : c; + return *this; + } + int first_column() const noexcept { return firstCol_; } + + /** @brief determines the rightmost border of the text body */ + formatting_ostream& last_column(int c) { + lastCol_ = c < 0 ? 0 : c; + return *this; + } + + int last_column() const noexcept { return lastCol_; } + + int text_width() const noexcept { + return lastCol_ - firstCol_; + } + + /** @brief additional indentation for the 2nd, 3rd, ... line of + a paragraph (sequence of soft-wrapped lines) */ + formatting_ostream& hanging_indent(int amount) { + hangingIndent_ = amount; + return *this; + } + int hanging_indent() const noexcept { + return hangingIndent_; + } + + /** @brief amount of blank lines between paragraphs */ + formatting_ostream& paragraph_spacing(int lines) { + paragraphSpacing_ = lines; + return *this; + } + int paragraph_spacing() const noexcept { + return paragraphSpacing_; + } + + /** @brief insert paragraph spacing + if paragraph is at least 'lines' lines long */ + formatting_ostream& min_paragraph_lines_for_spacing(int lines) { + paragraphSpacingThreshold_ = lines; + return *this; + } + int min_paragraph_lines_for_spacing() const noexcept { + return paragraphSpacingThreshold_; + } + + /** @brief if set to true, newline characters will be ignored */ + formatting_ostream& ignore_newline_chars(bool yes) { + ignoreInputNls_ = yes; + return *this; + } + + bool ignore_newline_chars() const noexcept { + return ignoreInputNls_; + } + + + //--------------------------------------------------------------- + /* @brief insert 'n' spaces */ + void write_spaces(int n) { + if(n < 1) return; + os_ << string_type(size_type(n), ' '); + curCol_ += n; + } + + /* @brief go to new line, but continue current paragraph */ + void wrap_soft(int times = 1) { + if(times < 1) return; + if(times > 1) { + os_ << string_type(size_type(times), '\n'); + } else { + os_ << '\n'; + } + curCol_ = 0; + ++curParagraphLines_; + } + + /* @brief go to new line, and start a new paragraph */ + void wrap_hard(int times = 1) { + if(times < 1) return; + + if(paragraph_spacing() > 0 && + paragraph_lines() >= min_paragraph_lines_for_spacing()) + { + times = paragraph_spacing() + 1; + } + + if(times > 1) { + os_ << string_type(size_type(times), '\n'); + curBlankLines_ += times - 1; + } else { + os_ << '\n'; + } + if(at_begin_of_line()) { + ++curBlankLines_; + } + curCol_ = 0; + curParagraphLines_ = 1; + } + + + //--------------------------------------------------------------- + bool at_begin_of_line() const noexcept { + return curCol_ <= current_line_begin(); + } + int current_line_begin() const noexcept { + return in_hanging_part_of_paragraph() + ? firstCol_ + hangingIndent_ + : firstCol_; + } + + int current_column() const noexcept { + return curCol_; + } + + int total_non_blank_lines() const noexcept { + return totalNonBlankLines_; + } + int paragraph_lines() const noexcept { + return curParagraphLines_; + } + int blank_lines_before_paragraph() const noexcept { + return curBlankLines_; + } + + + //--------------------------------------------------------------- + template + friend formatting_ostream& + operator << (formatting_ostream& os, const T& x) { + os.write(x); + return os; + } + + void flush() { + os_.flush(); + } + + +private: + bool in_hanging_part_of_paragraph() const noexcept { + return hanging_indent() > 0 && paragraph_lines() > 1; + } + bool current_line_empty() const noexcept { + return curCol_ < 1; + } + bool left_of_text_area() const noexcept { + return curCol_ < current_line_begin(); + } + bool right_of_text_area() const noexcept { + return curCol_ > lastCol_; + } + int columns_left_in_line() const noexcept { + return lastCol_ - std::max(current_line_begin(), curCol_); + } + + void fix_indent() { + if(left_of_text_area()) { + const auto fst = current_line_begin(); + write_spaces(fst - curCol_); + curCol_ = fst; + } + } + + template + bool only_whitespace(Iter first, Iter last) const { + return last == std::find_if_not(first, last, + [](char_type c) { return std::isspace(c); }); + } + + /** @brief write any object */ + template + void write(const T& x) { + std::ostringstream ss; + ss << x; + write(std::move(ss).str()); + } + + /** @brief write a stringstream */ + void write(const std::ostringstream& s) { + write(s.str()); + } + + /** @brief write a string */ + void write(const string_type& s) { + write(s.begin(), s.end()); + } + + /** @brief partition output into lines */ + template + void write(Iter first, Iter last) + { + if(first == last) return; + if(*first == '\n') { + if(!ignore_newline_chars()) wrap_hard(); + ++first; + if(first == last) return; + } + auto i = std::find(first, last, '\n'); + if(i != last) { + if(ignore_newline_chars()) ++i; + if(i != last) { + write_line(first, i); + write(i, last); + } + } + else { + write_line(first, last); + } + } + + /** @brief handle line wrapping due to column constraints */ + template + void write_line(Iter first, Iter last) + { + if(first == last) return; + if(only_whitespace(first, last)) return; + + if(right_of_text_area()) wrap_soft(); + + if(at_begin_of_line()) { + //discard whitespace, it we start a new line + first = std::find_if(first, last, + [](char_type c) { return !std::isspace(c); }); + if(first == last) return; + } + + const auto n = int(std::distance(first,last)); + const auto m = columns_left_in_line(); + //if text to be printed is too long for one line -> wrap + if(n > m) { + //break before word, if break is mid-word + auto breakat = first + m; + while(breakat > first && !std::isspace(*breakat)) --breakat; + //could not find whitespace before word -> try after the word + if(!std::isspace(*breakat) && breakat == first) { + breakat = std::find_if(first+m, last, + [](char_type c) { return std::isspace(c); }); + } + if(breakat > first) { + if(curCol_ < 1) ++totalNonBlankLines_; + fix_indent(); + std::copy(first, breakat, std::ostream_iterator(os_)); + curBlankLines_ = 0; + } + if(breakat < last) { + wrap_soft(); + write_line(breakat, last); + } + } + else { + if(curCol_ < 1) ++totalNonBlankLines_; + fix_indent(); + std::copy(first, last, std::ostream_iterator(os_)); + curCol_ += n; + curBlankLines_ = 0; + } + } + + /** @brief write a single character */ + void write(char_type c) + { + if(c == '\n') { + if(!ignore_newline_chars()) wrap_hard(); + } + else { + if(at_begin_of_line()) ++totalNonBlankLines_; + fix_indent(); + os_ << c; + ++curCol_; + } + } + + OStream& os_; + int curCol_; + int firstCol_; + int lastCol_; + int hangingIndent_; + int paragraphSpacing_; + int paragraphSpacingThreshold_; + int curBlankLines_; + int curParagraphLines_; + int totalNonBlankLines_; + bool ignoreInputNls_; +}; + + +} + + + + +/*************************************************************************//** + * + * @brief generates usage lines + * + * @details lazily evaluated + * + *****************************************************************************/ +class usage_lines +{ +public: + using string = doc_string; + + usage_lines(const group& cli, string prefix = "", + const doc_formatting& fmt = doc_formatting{}) + : + cli_(cli), fmt_(fmt), prefix_(std::move(prefix)) + { + if(!prefix_.empty()) prefix_ += ' '; + } + + usage_lines(const group& cli, const doc_formatting& fmt): + usage_lines(cli, "", fmt) + {} + + usage_lines& ommit_outermost_group_surrounders(bool yes) { + ommitOutermostSurrounders_ = yes; + return *this; + } + bool ommit_outermost_group_surrounders() const { + return ommitOutermostSurrounders_; + } + + template + inline friend OStream& operator << (OStream& os, const usage_lines& p) { + p.write(os); + return os; + } + + string str() const { + std::ostringstream os; os << *this; return os.str(); + } + + +private: + using stream_t = detail::formatting_ostream<>; + const group& cli_; + doc_formatting fmt_; + string prefix_; + bool ommitOutermostSurrounders_ = false; + + + //----------------------------------------------------- + struct context { + group::depth_first_traverser pos; + std::stack separators; + std::stack postfixes; + int level = 0; + const group* outermost = nullptr; + bool linestart = false; + bool useOutermost = true; + int line = 0; + + bool is_singleton() const noexcept { + return linestart && pos.is_last_in_path(); + } + bool is_alternative() const noexcept { + return pos.parent().exclusive(); + } + }; + + + /***************************************************************//** + * + * @brief writes usage text for command line parameters + * + *******************************************************************/ + template + void write(OStream& os) const + { + detail::formatting_ostream fos(os); + fos.first_column(fmt_.first_column()); + fos.last_column(fmt_.last_column()); + + auto hindent = int(prefix_.size()); + if(fos.first_column() + hindent >= int(0.4 * fos.text_width())) { + hindent = fmt_.indent_size(); + } + fos.hanging_indent(hindent); + + fos.paragraph_spacing(fmt_.paragraph_spacing()); + fos.min_paragraph_lines_for_spacing(2); + fos.ignore_newline_chars(fmt_.ignore_newline_chars()); + + context cur; + cur.pos = cli_.begin_dfs(); + cur.linestart = true; + cur.level = cur.pos.level(); + cur.outermost = &cli_; + + write(fos, cur, prefix_); + } + + + /***************************************************************//** + * + * @brief writes usage text for command line parameters + * + * @param prefix all that goes in front of current things to print + * + *******************************************************************/ + template + void write(OStream& os, context cur, string prefix) const + { + if(!cur.pos) return; + + std::ostringstream buf; + if(cur.linestart) buf << prefix; + const auto initPos = buf.tellp(); + + cur.level = cur.pos.level(); + + if(cur.useOutermost) { + //we cannot start outside of the outermost group + //so we have to treat it separately + start_group(buf, cur.pos.parent(), cur); + if(!cur.pos) { + os << buf.str(); + return; + } + } + else { + //don't visit siblings of starter node + cur.pos.skip_siblings(); + } + check_end_group(buf, cur); + + do { + if(buf.tellp() > initPos) cur.linestart = false; + if(!cur.linestart && !cur.pos.is_first_in_parent()) { + buf << cur.separators.top(); + } + if(cur.pos->is_group()) { + start_group(buf, cur.pos->as_group(), cur); + if(!cur.pos) { + os << buf.str(); + return; + } + } + else { + buf << param_label(cur.pos->as_param(), cur); + ++cur.pos; + } + check_end_group(buf, cur); + } while(cur.pos); + + os << buf.str(); + } + + + /***************************************************************//** + * + * @brief handles pattern group surrounders and separators + * and alternative splitting + * + *******************************************************************/ + void start_group(std::ostringstream& os, + const group& group, context& cur) const + { + //does cur.pos already point to a member or to group itself? + //needed for special treatment of outermost group + const bool alreadyInside = &(cur.pos.parent()) == &group; + + auto lbl = joined_label(group, cur); + if(!lbl.empty()) { + os << lbl; + cur.linestart = false; + //skip over entire group as its label has already been created + if(alreadyInside) { + cur.pos.next_after_siblings(); + } else { + cur.pos.next_sibling(); + } + } + else { + const bool splitAlternatives = group.exclusive() && + fmt_.split_alternatives() && + std::any_of(group.begin(), group.end(), + [this](const pattern& p) { + return int(p.param_count()) >= fmt_.alternatives_min_split_size(); + }); + + if(splitAlternatives) { + cur.postfixes.push(""); + cur.separators.push(""); + //recursively print alternative paths in decision-DAG + //enter group? + if(!alreadyInside) ++cur.pos; + cur.linestart = true; + cur.useOutermost = false; + auto pfx = os.str(); + os.str(""); + //print paths in DAG starting at each group member + for(std::size_t i = 0; i < group.size(); ++i) { + std::stringstream buf; + cur.outermost = cur.pos->is_group() ? &(cur.pos->as_group()) : nullptr; + write(buf, cur, pfx); + if(buf.tellp() > int(pfx.size())) { + os << buf.str(); + if(i < group.size()-1) { + if(cur.line > 0) { + os << string(fmt_.line_spacing(), '\n'); + } + ++cur.line; + os << '\n'; + } + } + cur.pos.next_sibling(); //do not descend into members + } + cur.pos.invalidate(); //signal end-of-path + return; + } + else { + //pre & postfixes, separators + auto surround = group_surrounders(group, cur); + os << surround.first; + cur.postfixes.push(std::move(surround.second)); + cur.separators.push(group_separator(group, fmt_)); + //descend into group? + if(!alreadyInside) ++cur.pos; + } + } + cur.level = cur.pos.level(); + } + + + /***************************************************************//** + * + *******************************************************************/ + void check_end_group(std::ostringstream& os, context& cur) const + { + for(; cur.level > cur.pos.level(); --cur.level) { + os << cur.postfixes.top(); + cur.postfixes.pop(); + cur.separators.pop(); + } + cur.level = cur.pos.level(); + } + + + /***************************************************************//** + * + * @brief makes usage label for one command line parameter + * + *******************************************************************/ + string param_label(const parameter& p, const context& cur) const + { + const auto& parent = cur.pos.parent(); + + const bool startsOptionalSequence = + parent.size() > 1 && p.blocking() && cur.pos.is_first_in_parent(); + + const bool outermost = + ommitOutermostSurrounders_ && cur.outermost == &parent; + + const bool showopt = !cur.is_alternative() && !p.required() + && !startsOptionalSequence && !outermost; + + const bool showrep = p.repeatable() && !outermost; + + string lbl; + + if(showrep) lbl += fmt_.repeat_prefix(); + if(showopt) lbl += fmt_.optional_prefix(); + + const auto& flags = p.flags(); + if(!flags.empty()) { + const int n = std::min(fmt_.max_flags_per_param_in_usage(), + int(flags.size())); + + const bool surrAlt = n > 1 && !showopt && !cur.is_singleton(); + + if(surrAlt) lbl += fmt_.alternative_flags_prefix(); + bool sep = false; + for(int i = 0; i < n; ++i) { + if(sep) { + if(cur.is_singleton()) + lbl += fmt_.alternative_group_separator(); + else + lbl += fmt_.flag_separator(); + } + lbl += flags[i]; + sep = true; + } + if(surrAlt) lbl += fmt_.alternative_flags_postfix(); + } + else { + if(!p.label().empty()) { + lbl += fmt_.label_prefix() + + p.label() + + fmt_.label_postfix(); + } else if(!fmt_.empty_label().empty()) { + lbl += fmt_.label_prefix() + + fmt_.empty_label() + + fmt_.label_postfix(); + } else { + return ""; + } + } + + if(showopt) lbl += fmt_.optional_postfix(); + if(showrep) lbl += fmt_.repeat_postfix(); + + return lbl; + } + + + /***************************************************************//** + * + * @brief prints flags in one group in a merged fashion + * + *******************************************************************/ + string joined_label(const group& g, const context& cur) const + { + if(!fmt_.merge_alternative_flags_with_common_prefix() && + !fmt_.merge_joinable_with_common_prefix()) return ""; + + const bool flagsonly = std::all_of(g.begin(), g.end(), + [](const pattern& p){ + return p.is_param() && !p.as_param().flags().empty(); + }); + + if(!flagsonly) return ""; + + const bool showOpt = g.all_optional() && + !(ommitOutermostSurrounders_ && cur.outermost == &g); + + auto pfx = g.common_flag_prefix(); + if(pfx.empty()) return ""; + + const auto n = pfx.size(); + if(g.exclusive() && + fmt_.merge_alternative_flags_with_common_prefix()) + { + string lbl; + if(showOpt) lbl += fmt_.optional_prefix(); + lbl += pfx + fmt_.alternatives_prefix(); + bool first = true; + for(const auto& p : g) { + if(p.is_param()) { + if(first) + first = false; + else + lbl += fmt_.alternative_param_separator(); + lbl += p.as_param().flags().front().substr(n); + } + } + lbl += fmt_.alternatives_postfix(); + if(showOpt) lbl += fmt_.optional_postfix(); + return lbl; + } + //no alternatives, but joinable flags + else if(g.joinable() && + fmt_.merge_joinable_with_common_prefix()) + { + const bool allSingleChar = std::all_of(g.begin(), g.end(), + [&](const pattern& p){ + return p.is_param() && + p.as_param().flags().front().substr(n).size() == 1; + }); + + if(allSingleChar) { + string lbl; + if(showOpt) lbl += fmt_.optional_prefix(); + lbl += pfx; + for(const auto& p : g) { + if(p.is_param()) + lbl += p.as_param().flags().front().substr(n); + } + if(showOpt) lbl += fmt_.optional_postfix(); + return lbl; + } + } + + return ""; + } + + + /***************************************************************//** + * + * @return symbols with which to surround a group + * + *******************************************************************/ + std::pair + group_surrounders(const group& group, const context& cur) const + { + string prefix; + string postfix; + + const bool isOutermost = &group == cur.outermost; + if(isOutermost && ommitOutermostSurrounders_) + return {string{}, string{}}; + + if(group.exclusive()) { + if(group.all_optional()) { + prefix = fmt_.optional_prefix(); + postfix = fmt_.optional_postfix(); + if(group.all_flagless()) { + prefix += fmt_.label_prefix(); + postfix = fmt_.label_prefix() + postfix; + } + } else if(group.all_flagless()) { + prefix = fmt_.label_prefix(); + postfix = fmt_.label_postfix(); + } else if(!cur.is_singleton() || !isOutermost) { + prefix = fmt_.alternatives_prefix(); + postfix = fmt_.alternatives_postfix(); + } + } + else if(group.size() > 1 && + group.front().blocking() && !group.front().required()) + { + prefix = fmt_.optional_prefix(); + postfix = fmt_.optional_postfix(); + } + else if(group.size() > 1 && cur.is_alternative() && + &group != cur.outermost) + { + prefix = fmt_.group_prefix(); + postfix = fmt_.group_postfix(); + } + else if(!group.exclusive() && + group.joinable() && !cur.linestart) + { + prefix = fmt_.joinable_prefix(); + postfix = fmt_.joinable_postfix(); + } + + if(group.repeatable()) { + if(prefix.empty()) prefix = fmt_.group_prefix(); + prefix = fmt_.repeat_prefix() + prefix; + if(postfix.empty()) postfix = fmt_.group_postfix(); + postfix += fmt_.repeat_postfix(); + } + + return {std::move(prefix), std::move(postfix)}; + } + + + /***************************************************************//** + * + * @return symbol that separates members of a group + * + *******************************************************************/ + static string + group_separator(const group& group, const doc_formatting& fmt) + { + const bool only1ParamPerMember = std::all_of(group.begin(), group.end(), + [](const pattern& p) { return p.param_count() < 2; }); + + if(only1ParamPerMember) { + if(group.exclusive()) { + return fmt.alternative_param_separator(); + } else { + return fmt.param_separator(); + } + } + else { //there is at least one large group inside + if(group.exclusive()) { + return fmt.alternative_group_separator(); + } else { + return fmt.group_separator(); + } + } + } +}; + + + + +/*************************************************************************//** + * + * @brief generates parameter and group documentation from docstrings + * + * @details lazily evaluated + * + *****************************************************************************/ +class documentation +{ +public: + using string = doc_string; + using filter_function = std::function; + + documentation(const group& cli, + const doc_formatting& fmt = doc_formatting{}, + filter_function filter = param_filter{}) + : + cli_(cli), fmt_{fmt}, usgFmt_{fmt}, filter_{std::move(filter)} + { + //necessary, because we re-use "usage_lines" to generate + //labels for documented groups + usgFmt_.max_flags_per_param_in_usage( + usgFmt_.max_flags_per_param_in_doc()); + } + + documentation(const group& cli, filter_function filter) : + documentation{cli, doc_formatting{}, std::move(filter)} + {} + + documentation(const group& cli, const param_filter& filter) : + documentation{cli, doc_formatting{}, + [filter](const parameter& p) { return filter(p); }} + {} + + template + inline friend OStream& operator << (OStream& os, const documentation& p) { + p.write(os); + return os; + } + + string str() const { + std::ostringstream os; + write(os); + return os.str(); + } + + +private: + using dfs_traverser = group::depth_first_traverser; + + const group& cli_; + doc_formatting fmt_; + doc_formatting usgFmt_; + filter_function filter_; + enum class paragraph { param, group }; + + + /***************************************************************//** + * + * @brief writes documentation to output stream + * + *******************************************************************/ + template + void write(OStream& os) const { + detail::formatting_ostream fos(os); + fos.first_column(fmt_.first_column()); + fos.last_column(fmt_.last_column()); + fos.hanging_indent(0); + fos.paragraph_spacing(0); + fos.ignore_newline_chars(fmt_.ignore_newline_chars()); + print_doc(fos, cli_); + } + + + /***************************************************************//** + * + * @brief writes full documentation text for command line parameters + * + *******************************************************************/ + template + void print_doc(detail::formatting_ostream& os, + const group& cli, int indentLvl = 0) const + { + if(cli.empty()) return; + + //if group itself doesn't have docstring + if(cli.doc().empty()) { + for(const auto& p : cli) { + print_doc(os, p, indentLvl); + } + } + else { //group itself does have docstring + bool anyDocInside = std::any_of(cli.begin(), cli.end(), + [](const pattern& p){ return !p.doc().empty(); }); + + if(anyDocInside) { //group docstring as title, then child entries + handle_spacing(os, paragraph::group, indentLvl); + os << cli.doc(); + for(const auto& p : cli) { + print_doc(os, p, indentLvl + 1); + } + } + else { //group label first then group docstring + auto lbl = usage_lines(cli, usgFmt_) + .ommit_outermost_group_surrounders(true).str(); + + str::trim(lbl); + handle_spacing(os, paragraph::param, indentLvl); + print_entry(os, lbl, cli.doc()); + } + } + } + + + /***************************************************************//** + * + * @brief writes documentation text for one group or parameter + * + *******************************************************************/ + template + void print_doc(detail::formatting_ostream& os, + const pattern& ptrn, int indentLvl) const + { + if(ptrn.is_group()) { + print_doc(os, ptrn.as_group(), indentLvl); + } + else { + const auto& p = ptrn.as_param(); + if(!filter_(p)) return; + + handle_spacing(os, paragraph::param, indentLvl); + print_entry(os, param_label(p, fmt_), p.doc()); + } + } + + /***************************************************************//** + * + * @brief handles line and paragraph spacings + * + *******************************************************************/ + template + void handle_spacing(detail::formatting_ostream& os, + paragraph p, int indentLvl) const + { + const auto oldIndent = os.first_column(); + const auto indent = fmt_.first_column() + indentLvl * fmt_.indent_size(); + + if(os.total_non_blank_lines() < 1) { + os.first_column(indent); + return; + } + + if(os.paragraph_lines() > 1 || indent < oldIndent) { + os.wrap_hard(fmt_.paragraph_spacing() + 1); + } else { + os.wrap_hard(); + } + + if(p == paragraph::group) { + if(os.blank_lines_before_paragraph() < fmt_.paragraph_spacing()) { + os.wrap_hard(fmt_.paragraph_spacing() - os.blank_lines_before_paragraph()); + } + } + else if(os.blank_lines_before_paragraph() < fmt_.line_spacing()) { + os.wrap_hard(fmt_.line_spacing() - os.blank_lines_before_paragraph()); + } + os.first_column(indent); + } + + /*********************************************************************//** + * + * @brief prints one entry = label + docstring + * + ************************************************************************/ + template + void print_entry(detail::formatting_ostream& os, + const string& label, const string& docstr) const + { + if(label.empty()) return; + + os << label; + + if(!docstr.empty()) { + if(os.current_column() >= fmt_.doc_column()) os.wrap_soft(); + const auto oldcol = os.first_column(); + os.first_column(fmt_.doc_column()); + os << docstr; + os.first_column(oldcol); + } + } + + + /*********************************************************************//** + * + * @brief makes label for one parameter + * + ************************************************************************/ + static doc_string + param_label(const parameter& param, const doc_formatting& fmt) + { + doc_string lbl; + + if(param.repeatable()) lbl += fmt.repeat_prefix(); + + const auto& flags = param.flags(); + if(!flags.empty()) { + lbl += flags[0]; + const int n = std::min(fmt.max_flags_per_param_in_doc(), + int(flags.size())); + for(int i = 1; i < n; ++i) { + lbl += fmt.flag_separator() + flags[i]; + } + } + else if(!param.label().empty() || !fmt.empty_label().empty()) { + lbl += fmt.label_prefix(); + if(!param.label().empty()) { + lbl += param.label(); + } else { + lbl += fmt.empty_label(); + } + lbl += fmt.label_postfix(); + } + + if(param.repeatable()) lbl += fmt.repeat_postfix(); + + return lbl; + } + +}; + + + + +/*************************************************************************//** + * + * @brief stores strings for man page sections + * + *****************************************************************************/ +class man_page +{ +public: + //--------------------------------------------------------------- + using string = doc_string; + + //--------------------------------------------------------------- + /** @brief man page section */ + class section { + public: + using string = doc_string; + + section(string stitle, string scontent): + title_{std::move(stitle)}, content_{std::move(scontent)} + {} + + const string& title() const noexcept { return title_; } + const string& content() const noexcept { return content_; } + + private: + string title_; + string content_; + }; + +private: + using section_store = std::vector
; + +public: + //--------------------------------------------------------------- + using value_type = section; + using const_iterator = section_store::const_iterator; + using size_type = section_store::size_type; + + + //--------------------------------------------------------------- + man_page& + append_section(string title, string content) + { + sections_.emplace_back(std::move(title), std::move(content)); + return *this; + } + //----------------------------------------------------- + man_page& + prepend_section(string title, string content) + { + sections_.emplace(sections_.begin(), + std::move(title), std::move(content)); + return *this; + } + + + //--------------------------------------------------------------- + const section& operator [] (size_type index) const noexcept { + return sections_[index]; + } + + //--------------------------------------------------------------- + size_type size() const noexcept { return sections_.size(); } + + bool empty() const noexcept { return sections_.empty(); } + + + //--------------------------------------------------------------- + const_iterator begin() const noexcept { return sections_.begin(); } + const_iterator end() const noexcept { return sections_.end(); } + + + //--------------------------------------------------------------- + man_page& program_name(const string& n) { + progName_ = n; + return *this; + } + man_page& program_name(string&& n) { + progName_ = std::move(n); + return *this; + } + const string& program_name() const noexcept { + return progName_; + } + + + //--------------------------------------------------------------- + man_page& section_row_spacing(int rows) { + sectionSpc_ = rows > 0 ? rows : 0; + return *this; + } + int section_row_spacing() const noexcept { return sectionSpc_; } + + +private: + int sectionSpc_ = 1; + section_store sections_; + string progName_; +}; + + + +/*************************************************************************//** + * + * @brief generates man sections from command line parameters + * with sections "synopsis" and "options" + * + *****************************************************************************/ +inline man_page +make_man_page(const group& cli, + doc_string progname = "", + const doc_formatting& fmt = doc_formatting{}) +{ + man_page man; + man.append_section("SYNOPSIS", usage_lines(cli,progname,fmt).str()); + man.append_section("OPTIONS", documentation(cli,fmt).str()); + return man; +} + + + +/*************************************************************************//** + * + * @brief generates man page based on command line parameters + * + *****************************************************************************/ +template +OStream& +operator << (OStream& os, const man_page& man) +{ + bool first = true; + const auto secSpc = doc_string(man.section_row_spacing() + 1, '\n'); + for(const auto& section : man) { + if(!section.content().empty()) { + if(first) first = false; else os << secSpc; + if(!section.title().empty()) os << section.title() << '\n'; + os << section.content(); + } + } + os << '\n'; + return os; +} + + + + + +/*************************************************************************//** + * + * @brief printing methods for debugging command line interfaces + * + *****************************************************************************/ +namespace debug { + + +/*************************************************************************//** + * + * @brief prints first flag or value label of a parameter + * + *****************************************************************************/ +inline doc_string doc_label(const parameter& p) +{ + if(!p.flags().empty()) return p.flags().front(); + if(!p.label().empty()) return p.label(); + return doc_string{""}; +} + +inline doc_string doc_label(const group&) +{ + return ""; +} + +inline doc_string doc_label(const pattern& p) +{ + return p.is_group() ? doc_label(p.as_group()) : doc_label(p.as_param()); +} + + +/*************************************************************************//** + * + * @brief prints parsing result + * + *****************************************************************************/ +template +void print(OStream& os, const parsing_result& result) +{ + for(const auto& m : result) { + os << "#" << m.index() << " " << m.arg() << " -> "; + auto p = m.param(); + if(p) { + os << doc_label(*p) << " \t"; + if(m.repeat() > 0) { + os << (m.bad_repeat() ? "[bad repeat " : "[repeat ") + << m.repeat() << "]"; + } + if(m.blocked()) os << " [blocked]"; + if(m.conflict()) os << " [conflict]"; + os << '\n'; + } + else { + os << " [unmapped]\n"; + } + } + + for(const auto& m : result.missing()) { + auto p = m.param(); + if(p) { + os << doc_label(*p) << " \t"; + os << " [missing after " << m.after_index() << "]\n"; + } + } +} + + +/*************************************************************************//** + * + * @brief prints parameter label and some properties + * + *****************************************************************************/ +template +void print(OStream& os, const parameter& p) +{ + if(p.greedy()) os << '!'; + if(p.blocking()) os << '~'; + if(!p.required()) os << '['; + os << doc_label(p); + if(p.repeatable()) os << "..."; + if(!p.required()) os << "]"; +} + + +//------------------------------------------------------------------- +template +void print(OStream& os, const group& g, int level = 0); + + +/*************************************************************************//** + * + * @brief prints group or parameter; uses indentation + * + *****************************************************************************/ +template +void print(OStream& os, const pattern& param, int level = 0) +{ + if(param.is_group()) { + print(os, param.as_group(), level); + } + else { + os << doc_string(4*level, ' '); + print(os, param.as_param()); + } +} + + +/*************************************************************************//** + * + * @brief prints group and its contents; uses indentation + * + *****************************************************************************/ +template +void print(OStream& os, const group& g, int level) +{ + auto indent = doc_string(4*level, ' '); + os << indent; + if(g.blocking()) os << '~'; + if(g.joinable()) os << 'J'; + os << (g.exclusive() ? "(|\n" : "(\n"); + for(const auto& p : g) { + print(os, p, level+1); + } + os << '\n' << indent << (g.exclusive() ? "|)" : ")"); + if(g.repeatable()) os << "..."; + os << '\n'; +} + + +} // namespace debug +} //namespace clipp + +#endif + diff --git a/libs/int2048/CMakeLists.txt b/libs/int2048/CMakeLists.txt new file mode 100644 index 0000000..bb0394e --- /dev/null +++ b/libs/int2048/CMakeLists.txt @@ -0,0 +1,4 @@ +set(PROJECT_NAME ${CMAKE_PROJECT_NAME}) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_FLAGS "-O2") +add_library(int2048 STATIC int2048.cpp) \ No newline at end of file diff --git a/libs/int2048/int2048.cpp b/libs/int2048/int2048.cpp new file mode 100644 index 0000000..78baae4 --- /dev/null +++ b/libs/int2048/int2048.cpp @@ -0,0 +1,931 @@ +/** + * @file int2048.cpp --- 2048-bit integer class implementation + * + * @details This file contains the implementation of the 2048-bit integer class. + * + * Codesytle: This file is written in a sytle mainly based on Google C++ Style + * Guide. As I use Clang-format to format my code, so the code style may be a + * little bit strange sometimes, in that case I'll manually format the + * code.What's sepecial is the comment: + * 1. Multi-line comments are always before the code they comment on. + * Usually the code they comment on is a complex procedure,like the definition + * of a function,a class or a variable with complex operation. If a multi-line + * comment is in one line, it will start with "/*" instead of "/**",otherwise it + * will start with "/**" and in the format of Doxygen. + * 2. Single-line comments are always after the code they comment on. + * Usually they are in the same line with the code they comment on,but sometimes + * they may come in the next lines. single-line comments shouldn't exceed 3 + * lines as they are intended to be short and easy to understand. + * 3. Temporary disabled code will be marked with "//" in the front of each + * 4. Some comments have special meanings,like "//TODO", "//FIXME", "//XXX","// + * clang-format off" and "// clang-format on". They are not controlled by the + * previous rules. + */ +#include "int2048.h" + +#include +#include +#include +#include +#include +#include + +static_assert(sizeof(int) == 4, "sizeof(int) != 4"); +static_assert(sizeof(long long) == 8, "sizeof(long long)!=8"); +namespace ZYM { +// 构造函数 +int2048::int2048() { + // 实现构造函数逻辑 + buf_length = kDefaultLength; + val = new int[buf_length](); + flag = 1; + num_length = 1; +} +int2048::~int2048() { + // 实现析构函数逻辑 + if (val != nullptr) delete[] val; +} + +int2048::int2048(long long input_value) { + // 实现构造函数逻辑 + buf_length = kDefaultLength; + val = new int[buf_length](); + if (input_value < 0) { + flag = -1; + input_value = -input_value; + } else + flag = 1; + if (input_value == 0) { + num_length = 1; + return; + } + num_length = 0; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + while (input_value > 0) { + val[num_length / kNum] += (input_value % 10) * kPow10[num_length % kNum]; + input_value /= 10; + num_length++; + } +} + +int2048::int2048(const std::string &input_value) { + // 实现构造函数逻辑 + buf_length = (input_value.length() + kNum - 1) / kNum * kMemAdditionScalar; + val = new int[buf_length](); + flag = 1; + num_length = 0; + if (input_value[0] == '-') { + flag = -1; + } + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + int read_highest_pos = (flag > 0 ? 0 : 1); + while (input_value[read_highest_pos] == '0' && + read_highest_pos + 1 < input_value.length()) + read_highest_pos++; + for (int i = input_value.length() - 1; i >= read_highest_pos; i--) { + val[num_length / kNum] += + (input_value[i] - '0') * kPow10[num_length % kNum]; + num_length++; + } + if (num_length == 1 && val[0] == 0) flag = 1; +} + +int2048::int2048(const int2048 &input_value) { + buf_length = input_value.buf_length; + val = new int[buf_length](); + memcpy(val, input_value.val, buf_length * sizeof(int)); + flag = input_value.flag; + num_length = input_value.num_length; +} + +/** + * @brief Move constructor + * + * @param input_value + * + * @details Note that after moving, the input_value will be set to 0. + */ +int2048::int2048(int2048 &&input_value) noexcept { + buf_length = input_value.buf_length; + val = input_value.val; + flag = input_value.flag; + num_length = input_value.num_length; + input_value.buf_length = kDefaultLength; + input_value.flag = 1; + input_value.num_length = 1; + input_value.val = new int[input_value.buf_length](); +} + +// 读入一个大整数 +void int2048::read(const std::string &input_value) { + delete[] val; + buf_length = (input_value.length() + kNum - 1) / kNum * kMemAdditionScalar; + val = new int[buf_length](); + flag = 1; + num_length = 0; + if (input_value[0] == '-') { + flag = -1; + } + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + int read_highest_pos = (flag > 0 ? 0 : 1); + while (input_value[read_highest_pos] == '0' && + read_highest_pos + 1 < input_value.length()) + read_highest_pos++; + for (int i = input_value.length() - 1; i >= read_highest_pos; i--) { + val[num_length / kNum] += + (input_value[i] - '0') * kPow10[num_length % kNum]; + num_length++; + } + if (num_length == 1 && val[0] == 0) flag = 1; +} + +// 输出储存的大整数,无需换行 +void int2048::print() { + // 实现输出逻辑 + char *buf = new char[num_length + 5]; + char *p = buf; + if (flag == -1) *p++ = '-'; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + for (int i = num_length - 1; i >= 0; i--) + *p++ = char('0' + val[i / int2048::kNum] / kPow10[i % int2048::kNum] % 10); + *p++ = 0; + std::cout << buf; + delete[] buf; +} + +void int2048::print_debug() { + // 实现输出逻辑 + char *buf = new char[num_length + 5]; + char *p = buf; + if (flag == -1) *p++ = '-'; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + for (int i = num_length - 1; i >= 0; i--) + *p++ = char('0' + val[i / int2048::kNum] / kPow10[i % int2048::kNum] % 10); + *p++ = 0; + std::cerr << buf << std::endl; + delete[] buf; +} + +/** + * @brief Claim memory for the number + * + * @param number_length The length of the number + * + * @details If the number_length is smaller than the current buf_length/4 or + * bigger than current buf_length, then val will be reset to accomodate + * number_length*2 numbers. Something like std::vector. + */ +void int2048::ClaimMem(size_t number_length) { + size_t new_number_blocks = (number_length + kNum - 1) / kNum; + if (new_number_blocks > buf_length) { + int *new_val = new int[new_number_blocks * kMemAdditionScalar](); + memcpy(new_val, val, buf_length * sizeof(int)); + delete[] val; + val = new_val; + buf_length = new_number_blocks * kMemAdditionScalar; + } else if (new_number_blocks * kMemDeleteScalar < buf_length) { + int *new_val = new int[new_number_blocks * kMemAdditionScalar](); + memcpy(new_val, val, new_number_blocks * sizeof(int)); + delete[] val; + val = new_val; + buf_length = new_number_blocks * kMemAdditionScalar; + } +} + +/** + * @brief Compare two unsigned numbers + * + * @param A The first number + * @param B The second number + * + * @return -1 if A < B, 0 if A == B, 1 if A > B + * + * @details This function is used to compare two numbers wittout considering the + * sign. + */ +inline int UnsignedCmp(const int2048 &A, const int2048 &B) { + if (A.num_length != B.num_length) return A.num_length < B.num_length ? -1 : 1; + int number_of_blocks = (A.num_length + int2048::kNum - 1) / int2048::kNum; + for (int i = number_of_blocks - 1; i >= 0; i--) + if (A.val[i] != B.val[i]) return A.val[i] < B.val[i] ? -1 : 1; + return 0; +} + +inline void UnsignedAdd(int2048 &A, const int2048 *const pB) { + if (&A == pB) throw "UnsignedAdd: A and B are the same object"; + A.ClaimMem(std::max(A.num_length, pB->num_length) + 2); + for (int i = 0; + i < (std::max(A.num_length, pB->num_length) + int2048::kNum - 1) / + int2048::kNum; + i++) { + if (i < (pB->num_length + int2048::kNum - 1) / int2048::kNum) + A.val[i] += pB->val[i]; + if (i + 1 < A.buf_length) A.val[i + 1] += A.val[i] / int2048::kStoreBase; + A.val[i] %= int2048::kStoreBase; + } + A.num_length = std::max(A.num_length, pB->num_length); + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + if (A.val[A.num_length / int2048::kNum] / + kPow10[A.num_length % int2048::kNum] > + 0) + A.num_length++; +} + +// 加上一个大整数 +int2048 &int2048::add(const int2048 &B) { + // 实现加法逻辑 + const int2048 *pB = &B; + if (this->flag == pB->flag) { + if (this == &B) pB = new int2048(B); + UnsignedAdd(*this, pB); + } else if (this->flag == 1 && pB->flag == -1) { + int cmp = UnsignedCmp(*this, *pB); + if (cmp >= 0) { + if (this == &B) pB = new int2048(B); + UnsignedMinus(*this, pB); + this->flag = 1; + } else { + int2048 new_B = std::move(*this); + *this = B; + UnsignedMinus(*this, &new_B); + this->flag = -1; + } + } else if (this->flag == -1 && pB->flag == 1) { + int cmp = UnsignedCmp(*this, *pB); + if (cmp >= 0) { + if (this == &B) pB = new int2048(B); + UnsignedMinus(*this, pB); + this->flag = -1; + if (this->num_length == 1 && this->val[0] == 0) this->flag = 1; + } else { + int2048 new_B = std::move(*this); + *this = B; + UnsignedMinus(*this, &new_B); + this->flag = 1; + } + } + if (pB != &B) delete pB; + return *this; +} + +// 返回两个大整数之和 +int2048 add(int2048 A, const int2048 &B) { + // 实现加法逻辑 + return std::move(A.add(B)); +} + +inline void UnsignedMinus(int2048 &A, const int2048 *const pB) { + if (&A == pB) throw "UnsignedMinus: A and B are the same object"; + for (int i = 0; i < (pB->num_length + int2048::kNum - 1) / int2048::kNum; + i++) { + A.val[i] -= pB->val[i]; + if (A.val[i] < 0) { + A.val[i] += int2048::kStoreBase; + A.val[i + 1]--; + } + } + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + int new_length = 0; + for (int i = 0; i < A.num_length; i++) + if (A.val[i / int2048::kNum] / kPow10[i % int2048::kNum] > 0) + new_length = i + 1; + A.num_length = new_length; + if (A.num_length == 0) A.num_length = 1; + A.ClaimMem(A.num_length); +} + +// 减去一个大整数 +int2048 &int2048::minus(const int2048 &B) { + // 实现减法逻辑 + const int2048 *pB = &B; + if (this->flag == B.flag) { + int cmp = UnsignedCmp(*this, *pB); + if (cmp >= 0) { + if (this == &B) pB = new int2048(B); + UnsignedMinus(*this, pB); + if (this->num_length == 1 && this->val[0] == 0) this->flag = 1; + } else { + int2048 new_B = std::move(*this); + *this = B; + UnsignedMinus(*this, &new_B); + this->flag = -this->flag; + if (this->num_length == 1 && this->val[0] == 0) this->flag = 1; + } + } else { + if (this == &B) pB = new int2048(B); + UnsignedAdd(*this, pB); + } + if (pB != &B) delete pB; + return *this; +} + +// 返回两个大整数之差 +int2048 minus(int2048 A, const int2048 &B) { + // 实现减法逻辑 + return std::move(A.minus(B)); +} + +// 运算符重载 + +int2048 int2048::operator+() const { + // 实现一元加法逻辑 + return std::move(int2048(*this)); +} + +int2048 int2048::operator-() const { + // 实现一元减法逻辑 + int2048 ret(*this); + if (!(ret.num_length == 1 && ret.val[0] == 0)) ret.flag = -ret.flag; + return std::move(ret); +} + +int2048 &int2048::operator=(const int2048 &B) { + // 实现赋值运算符逻辑 + // similar to int2048::int2048(const int2048 &input_value) + if (this == &B) return *this; + delete[] val; + buf_length = B.buf_length; + val = new int[buf_length](); + memcpy(val, B.val, buf_length * sizeof(int)); + flag = B.flag; + num_length = B.num_length; + return *this; +} + +int2048 &int2048::operator=(int2048 &&B) noexcept { + // 实现移动赋值运算符逻辑 + if (this == &B) return *this; + delete[] val; + buf_length = B.buf_length; + val = B.val; + flag = B.flag; + num_length = B.num_length; + B.buf_length = kDefaultLength; + B.flag = 1; + B.num_length = 1; + B.val = new int[B.buf_length](); + return *this; +} + +int2048 &int2048::operator+=(const int2048 &B) { + // 实现复合加法逻辑 + return this->add(B); +} + +int2048 operator+(int2048 A, const int2048 &B) { + // 实现加法逻辑 + A.add(B); + return std::move(A); +} + +int2048 &int2048::operator-=(const int2048 &B) { + // 实现复合减法逻辑 + return this->minus(B); +} + +int2048 operator-(int2048 A, const int2048 &B) { + // 实现减法逻辑 + A.minus(B); + return std::move(A); +} +__int128_t int2048::QuickPow(__int128_t v, long long q) { + __int128_t ret = 1; + v %= int2048::kNTTMod; + while (q > 0) { + if (q & 1) (ret *= v) %= int2048::kNTTMod; + (v *= v) %= int2048::kNTTMod; + q >>= 1; + } + return ret; +} + +/** + * @brief Move the number to the left by L digits. That is, v'=v*(10^L) + */ +void int2048::LeftMoveBy(int L) { + const static long long kPow10[9] = {1, 10, 100, + 1000, 10000, 100000, + 1000000, 10000000, 100000000}; + int big_move = L / int2048::kNum; + int small_move = L % int2048::kNum; + this->ClaimMem(this->num_length + L); + for (int i = this->buf_length - 1; i >= big_move; i--) { + this->val[i] = this->val[i - big_move]; + } + for (int i = 0; i < big_move; i++) { + this->val[i] = 0; + } + this->num_length += big_move * int2048::kNum; + if (small_move == 0) return; + for (int i = this->buf_length - 1; i >= 0; i--) { + this->val[i] = + ((long long)this->val[i] * kPow10[small_move]) % int2048::kStoreBase; + if (i - 1 >= 0) { + this->val[i] += this->val[i - 1] / kPow10[int2048::kNum - small_move]; + } + } + this->val[big_move] = + (this->val[big_move] / kPow10[small_move]) * kPow10[small_move]; + this->num_length += small_move; +} + +/** + * @brief Move the number to the right by L digits. That is, v'=v//(10^L) + */ +void int2048::RightMoveBy(int L) { + if (L >= this->num_length) { + this->num_length = 1; + this->val[0] = 0; + return; + } + int big_move = L / int2048::kNum; + int small_move = L % int2048::kNum; + for (int i = 0; i < this->buf_length - big_move; i++) { + this->val[i] = this->val[i + big_move]; + } + for (int i = this->buf_length - big_move; i < this->buf_length; i++) { + this->val[i] = 0; + } + this->num_length -= big_move * int2048::kNum; + if (small_move == 0) return; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + for (int i = 0; i < this->buf_length; i++) { + this->val[i] /= kPow10[small_move]; + if (i + 1 < this->buf_length) { + this->val[i] += this->val[i + 1] % kPow10[small_move] * + kPow10[int2048::kNum - small_move]; + } + } + this->num_length -= small_move; +} + +/** + * @brief the definition of NTTTransform + * + * @param a the array to be transformed + * @param NTT_blocks the length of the array + * @param inverse whether to do inverse transform + * + * @details the array a will be transformed to a new array a', which is the NTT. + * Note that the base in NTT is 10000. + */ +void int2048::NTTTransform(__int128_t *a, int NTT_blocks, + bool inverse = false) { + for (int i = 1, j = 0; i < NTT_blocks; i++) { + int bit = NTT_blocks >> 1; + while (j >= bit) { + j -= bit; + bit >>= 1; + } + j += bit; + if (i < j) std::swap(a[i], a[j]); + } + for (int len = 2; len <= NTT_blocks; len <<= 1) { + __int128_t wlen = QuickPow(int2048::kNTTRoot, (int2048::kNTTMod - 1) / len); + if (inverse) wlen = QuickPow(wlen, int2048::kNTTMod - 2); + for (int i = 0; i < NTT_blocks; i += len) { + __int128_t w = 1; + for (int j = 0; j < len / 2; j++) { + __int128_t u = a[i + j], v = a[i + j + len / 2] * w % int2048::kNTTMod; + a[i + j] = (u + v) % int2048::kNTTMod; + a[i + j + len / 2] = (u - v + int2048::kNTTMod) % int2048::kNTTMod; + (w *= wlen) %= int2048::kNTTMod; + } + } + } + if (inverse) { + __int128_t inv = QuickPow(NTT_blocks, int2048::kNTTMod - 2); + for (int i = 0; i < NTT_blocks; i++) (a[i] *= inv) %= int2048::kNTTMod; + } +} + +/** + * @brief Unsigned multiply two numbers + * + * @param A The first number + * @param pB The second number + * + * @details This function will multiply two numbers without considering the + * sign. + */ +inline void UnsignedMultiply(int2048 &A, const int2048 *pB) { + if (&A == pB) throw "UnsignedMultiply: A and B are the same object"; + int blocks_of_A = ((A.num_length + int2048::kNum - 1) / int2048::kNum); + int blocks_of_B = ((pB->num_length + int2048::kNum - 1) / int2048::kNum); + int max_blocks = blocks_of_A + blocks_of_B; + int NTT_blocks = 1; + while (NTT_blocks < (max_blocks << 1)) NTT_blocks <<= 1; + __int128_t *pDA = new __int128_t[NTT_blocks](); + __int128_t *pDB = new __int128_t[NTT_blocks](); + __int128_t *pDC = new __int128_t[NTT_blocks](); + for (int i = 0; i < blocks_of_A; i++) { + pDA[i << 1] = A.val[i] % int2048::kNTTBlcokBase; + pDA[(i << 1) | 1] = A.val[i] / int2048::kNTTBlcokBase; + } + for (int i = 0; i < blocks_of_B; i++) { + pDB[i << 1] = pB->val[i] % int2048::kNTTBlcokBase; + pDB[(i << 1) | 1] = pB->val[i] / int2048::kNTTBlcokBase; + } + A.NTTTransform(pDA, NTT_blocks); + A.NTTTransform(pDB, NTT_blocks); + for (int i = 0; i < NTT_blocks; i++) + pDC[i] = (pDA[i] * pDB[i]) % int2048::kNTTMod; + A.NTTTransform(pDC, NTT_blocks, true); + for (int i = 0; i < NTT_blocks - 1; i++) { + pDC[i + 1] += pDC[i] / int2048::kNTTBlcokBase; + pDC[i] %= int2048::kNTTBlcokBase; + } + if (pDC[NTT_blocks - 1] >= int2048::kNTTBlcokBase) + throw "UnsignedMultiply: NTT result overflow"; + int flag_store = A.flag; + A.ClaimMem(NTT_blocks * 4); + memset(A.val, 0, A.buf_length * sizeof(int)); + for (int i = 0; i < NTT_blocks / 2; i++) { + A.val[i] = pDC[(i << 1) | 1] * int2048::kNTTBlcokBase + pDC[i << 1]; + } + A.num_length = NTT_blocks * 4; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + while (A.val[(A.num_length - 1) / int2048::kNum] / + kPow10[(A.num_length - 1) % int2048::kNum] == + 0) { + A.num_length--; + if (A.num_length == 0) { + A.num_length = 1; + break; + } + } + delete[] pDA; + delete[] pDB; + delete[] pDC; +} + +int2048 &int2048::Multiply(const int2048 &B) { + // 实现复合乘法逻辑 + const int2048 *pB = &B; + if (this == &B) pB = new int2048(B); + if ((this->num_length == 1 && this->val[0] == 0) || + (pB->num_length == 1 && pB->val[0] == 0)) { + *this = std::move(int2048(0)); + if (pB != &B) delete pB; + return *this; + } + this->flag = this->flag * pB->flag; + UnsignedMultiply(*this, pB); + if (pB != &B) delete pB; + return *this; +} + +int2048 Multiply(int2048 A, const int2048 &B) { + // 实现乘法逻辑 + return std::move(A.Multiply(B)); +} + +int2048 &int2048::operator*=(const int2048 &B) { + // 实现复合乘法逻辑 + return this->Multiply(B); +} + +int2048 operator*(int2048 A, const int2048 &B) { + // 实现乘法逻辑 + A.Multiply(B); + return std::move(A); +} + +/** + * @brief Unsigned multiply a number by an integer + * + * @param v The integer + * + * @details This function will multiply a number by an integer without + * considering the sign. + */ +void int2048::UnsignedMultiplyByInt(int v) { + if (v < 0) throw "UnsignedMultiplyByInt: v < 0"; + if (v == 0) { + *this = std::move(int2048(0)); + return; + } + if (v == 1) return; + int blocks = (this->num_length + int2048::kNum - 1) / int2048::kNum; + this->ClaimMem(this->num_length + int2048::kNum * 2); + blocks += 2; + long long c = 0; + for (int i = 0; i < blocks; i++) { + long long tmp = (long long)this->val[i] * v + c; + c = tmp / int2048::kStoreBase; + this->val[i] = tmp % int2048::kStoreBase; + } + this->num_length = blocks * int2048::kNum; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + while (this->num_length > 1 && + this->val[(this->num_length - 1) / int2048::kNum] / + kPow10[(this->num_length - 1) % int2048::kNum] == + 0) + this->num_length--; +} + +/** + * @brief Estimate the inverse of B, which is the result of [10^2n/B] + */ +int2048 GetInv(const int2048 &B, int n) { + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + int total_blocks = (B.num_length + int2048::kNum - 1) / int2048::kNum; + if (n <= 16) { + /** + * This code block is used to calculate the inverse of B when n is small. + */ + long long b = 0; + for (int j = B.num_length - 1, i = 0; i < n; i++, j--) + b = b * 10 + (B.val[j / int2048::kNum] / kPow10[j % int2048::kNum]) % 10; + int2048 res; + res.ClaimMem((2 * n) + 1); + res.val[2 * n / int2048::kNum] = kPow10[2 * n % int2048::kNum]; + __uint128_t c = 0; + int tmp_B = (((2 * n) + 1) + int2048::kNum - 1) / int2048::kNum; + for (int i = tmp_B - 1; i >= 0; i--) { + c = c * int2048::kStoreBase + res.val[i]; + res.val[i] = c / b; + c %= b; + assert(res.val[i] < int2048::kStoreBase); + } + res.num_length = (2 * n) + 1; + while (res.num_length > 1 && + res.val[(res.num_length - 1) / int2048::kNum] / + kPow10[(res.num_length - 1) % int2048::kNum] == + 0) + res.num_length--; + return std::move(res); + } + int k = (n + 2) >> 1; + int2048 sub_soluton = std::move(GetInv(B, k)); + int2048 sub_soluton_copy_1(sub_soluton); + int2048 sub_soluton_copy_2(sub_soluton); + sub_soluton_copy_1.UnsignedMultiplyByInt(2); + sub_soluton_copy_1.LeftMoveBy((n - k)); + // Now sub_soluton_copy_1 is 2*sub_soluton*10^(n-k) + /*now we get the current B*/ + int2048 current_B; + current_B.ClaimMem(n); + for (int i = B.num_length - 1, j = n - 1; j >= 0; j--, i--) + current_B.val[j / int2048::kNum] += + (B.val[i / int2048::kNum] / kPow10[i % int2048::kNum] % 10) * + kPow10[j % int2048::kNum]; + // current_B is the highest n numbers of B + current_B.num_length = n; + // std::cerr << "n=" << n << " while B="; + // int2048 new_B = B; + // new_B.print_debug(); + // std::cerr << "current_B: "; + // current_B.print_debug(); + + UnsignedMultiply(sub_soluton_copy_2, ¤t_B); + UnsignedMultiply(sub_soluton_copy_2, &sub_soluton); + sub_soluton_copy_2.RightMoveBy(2 * k); + // Now sub_soluton_copy_2 is sub_soluton^2*current_B/(10^2k) + UnsignedMinus(sub_soluton_copy_1, &sub_soluton_copy_2); + int2048 res = sub_soluton_copy_1; + // Now we get an estimation for [10^2n/current_B] + /*Now begin doing some ajustments*/ + int2048 remain; + remain.ClaimMem((2 * n) + 1); + remain.val[2 * n / int2048::kNum] = kPow10[2 * n % int2048::kNum]; + remain.num_length = (2 * n) + 1; + UnsignedMultiply(sub_soluton_copy_1, ¤t_B); + int cmp = UnsignedCmp(remain, sub_soluton_copy_1); + if (cmp == 0) return std::move(res); + if (cmp > 0) { + UnsignedMinus(remain, &sub_soluton_copy_1); + for (int i = 64; i > 0; i >>= 1) { + int2048 tmp_B(current_B); + tmp_B.UnsignedMultiplyByInt(i); + if (UnsignedCmp(remain, tmp_B) >= 0) { + res += i; + UnsignedMinus(remain, &tmp_B); + } + } + return std::move(res); + } else { + UnsignedMinus(sub_soluton_copy_1, &remain); + for (int i = 64; i > 0; i >>= 1) { + int2048 tmp_B(current_B); + tmp_B.UnsignedMultiplyByInt(i); + if (UnsignedCmp(sub_soluton_copy_1, tmp_B) >= 0) { + res -= i; + UnsignedMinus(sub_soluton_copy_1, &tmp_B); + } + } + int2048 tmp_zero(0); + if (UnsignedCmp(sub_soluton_copy_1, tmp_zero) != 0) res -= 1; + return std::move(res); + } +} + +/** + * @brief Unsigned divide two numbers + * + * @param A The first number + * @param pB The second number + * + * @details This function will divide two numbers without considering the sign. + * reference: + * + */ +inline void UnsignedDivide(int2048 &A, const int2048 *pB) { + int2048 B(*pB); + int L1 = A.num_length; + int L2 = B.num_length; + if (L2 <= 16) { + long long b = B.val[0] + (long long)B.val[1] * int2048::kStoreBase; + __uint128_t c = 0; + int blocks_of_A = (A.num_length + int2048::kNum - 1) / int2048::kNum; + for (int i = blocks_of_A - 1; i >= 0; i--) { + c = c * int2048::kStoreBase + A.val[i]; + A.val[i] = c / b; + c %= b; + assert(A.val[i] < int2048::kStoreBase); + } + A.num_length = blocks_of_A * int2048::kNum; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + while (A.num_length > 1 && + A.val[(A.num_length - 1) / int2048::kNum] / + kPow10[(A.num_length - 1) % int2048::kNum] == + 0) + A.num_length--; + return; + } + if (UnsignedCmp(A, *pB) < 0) { + A = std::move(int2048(0)); + return; + } + if (2 * L2 < L1) { + int delta = L1 - 2 * L2; + A.LeftMoveBy(delta); + L1 += delta; + B.LeftMoveBy(delta); + L2 += delta; + } + assert(L1 == A.num_length); + assert(L2 == B.num_length); + assert(2 * L2 >= L1); + /*Now we calculate [10^2n/B]*/ + int2048 res_hat = std::move(GetInv(B, L2)); + UnsignedMultiply(res_hat, &A); + res_hat.RightMoveBy(2 * L2); + // now res_hat is [[10^2n/B]*A/(10^2L2)] + /*Now begin doing ajustments*/ + int2048 remain(A), tmp_B(B); + UnsignedMultiply(tmp_B, &res_hat); + UnsignedMinus(remain, &tmp_B); + // now remain is A-res_hat*B + for (int i = 8; i > 0; i >>= 1) { + tmp_B = B; + tmp_B.UnsignedMultiplyByInt(i); + if (UnsignedCmp(remain, tmp_B) >= 0) { + res_hat += i; + UnsignedMinus(remain, &tmp_B); + } + } + A = std::move(res_hat); +} +int2048 &int2048::Divide(const int2048 &B) { + if (B.num_length == 1 && B.val[0] == 0) { + *this = std::move(int2048(0)); + return *this; + // throw "Divide: divide by zero"; + } + if (this == &B) { + *this = std::move(int2048(1)); + return *this; + } + int2048 origin_A(*this); + int flag_store = this->flag * B.flag; + UnsignedDivide(*this, &B); + this->flag = flag_store; + if (this->flag == -1) { + if (origin_A != (*this) * B) { + *this -= 1; + } + } + if (this->num_length == 1 && this->val[0] == 0) this->flag = 1; + return *this; +} +int2048 Divide(int2048 A, const int2048 &B) { + A.Divide(B); + return std::move(A); +} + +int2048 &int2048::operator/=(const int2048 &B) { + // 实现复合除法逻辑 + return this->Divide(B); +} + +int2048 operator/(int2048 A, const int2048 &B) { + // 实现除法逻辑 + A.Divide(B); + return std::move(A); +} + +int2048 &int2048::operator%=(const int2048 &B) { + // 实现复合取模逻辑 + int2048 C(*this); + C.Divide(B); + this->minus(C.Multiply(B)); + return *this; +} + +int2048 operator%(int2048 A, const int2048 &B) { + // 实现取模逻辑 + int2048 C(A); + C.Divide(B); + A.minus(C.Multiply(B)); + return std::move(A); +} + +std::istream &operator>>(std::istream &stream, int2048 &V) { + // 实现输入运算符逻辑 + std::string v_str; + stream >> v_str; + V.read(v_str); + return stream; +} + +std::ostream &operator<<(std::ostream &stream, const int2048 &v) { + // 实现输出运算符逻辑 + char *buf = new char[v.num_length + 5]; + char *p = buf; + if (v.flag == -1) *p++ = '-'; + const static int kPow10[9] = {1, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000}; + for (int i = v.num_length - 1; i >= 0; i--) + *p++ = + char('0' + v.val[i / int2048::kNum] / kPow10[i % int2048::kNum] % 10); + *p++ = 0; + stream << buf; + delete[] buf; + return stream; +} + +bool operator==(const int2048 &A, const int2048 &B) { + // 实现等于运算符逻辑 + if (A.flag != B.flag) return false; + return UnsignedCmp(A, B) == 0; +} + +bool operator!=(const int2048 &A, const int2048 &B) { + // 实现不等于运算符逻辑 + if (A.flag != B.flag) return true; + return UnsignedCmp(A, B) != 0; +} + +bool operator<(const int2048 &A, const int2048 &B) { + // 实现小于运算符逻辑 + if (A.flag != B.flag) return A.flag < B.flag; + int cmp = UnsignedCmp(A, B); + if (A.flag == 1) + return cmp < 0; + else + return cmp > 0; +} + +bool operator>(const int2048 &A, const int2048 &B) { + // 实现大于运算符逻辑 + if (A.flag != B.flag) return A.flag > B.flag; + int cmp = UnsignedCmp(A, B); + if (A.flag == 1) + return cmp > 0; + else + return cmp < 0; +} + +bool operator<=(const int2048 &A, const int2048 &B) { + // 实现小于等于运算符逻辑 + if (A.flag != B.flag) return A.flag < B.flag; + int cmp = UnsignedCmp(A, B); + if (A.flag == 1) + return cmp <= 0; + else + return cmp >= 0; +} + +bool operator>=(const int2048 &A, const int2048 &B) { + // 实现大于等于运算符逻辑 + if (A.flag != B.flag) return A.flag > B.flag; + int cmp = UnsignedCmp(A, B); + if (A.flag == 1) + return cmp >= 0; + else + return cmp <= 0; +} +} // namespace ZYM \ No newline at end of file diff --git a/libs/int2048/int2048.h b/libs/int2048/int2048.h new file mode 100644 index 0000000..a4f7b81 --- /dev/null +++ b/libs/int2048/int2048.h @@ -0,0 +1,139 @@ +#pragma once +#ifndef SJTU_BIGINTEGER +#define SJTU_BIGINTEGER + +#include +#include +#include +#include +#include + +namespace ZYM { +class int2048 { + /** + * If the interger is negative, flag = -1, otherwise flag = 1. + * num_length is the length of the integer, (num_length+kNum-1)/kNum is the + * length of val with data. Note that position in val without data is 0. + * buf_length is the accessiable length of val. + */ + const static int kStoreBase = 100000000, kNum = 8, kDefaultLength = 10; + const static int kMemAdditionScalar = 2, kMemDeleteScalar = 4; + /** + * the follow data used by NTT is generated by this code: +#!/usr/bin/python3 +from sympy import isprime,primitive_root +found=False +for i in range(0,20): + for j in range(2**i,(2**(i+1))): + V=j*(2**(57-i))+1 + if isprime(V): + found=True + print(j,57-i) + print("number=",V) + print("root=",primitive_root(V)) + exit(0) + * it out puts: +95 55 +number= 180143985094819841 +root= 6 + */ + const static __int128_t kNTTMod = 180143985094819841ll; + const static __int128_t kNTTRoot = 6; + const static int kNTTBlockNum = 4; + const static int kNTTBlcokBase = 10000; + + size_t buf_length = 0; + int *val = nullptr; + signed char flag = +1; + int num_length = 0; + + __int128_t QuickPow(__int128_t v, long long q); + void NTTTransform(__int128_t *, int, bool); + friend int2048 GetInv(const int2048 &, int); + void UnsignedMultiplyByInt(int); + + public: + int2048(); + int2048(long long); + int2048(const std::string &); + int2048(const int2048 &); + int2048(int2048 &&) noexcept; + ~int2048(); + + /** + * @brief Move the integer left (*10^k) or right(//10^k). + */ + void LeftMoveBy(int); + void RightMoveBy(int); + + void read(const std::string &); + void print(); + void print_debug(); + // function print_debug is used to print the data in val to stderr(with '\n'), + // for debug + + void ClaimMem(size_t); + // something like vector's reserve + + /** + * Fuctions whose name starts with Unsigned are basic operation. It receives + * int2048& A and const int2048* pB(UnsignedCmp receives const int2048& B), + * and do the operation A op= *pB. Warning: the address of A and pB must be + * different. + */ + inline friend int UnsignedCmp(const int2048 &, const int2048 &); + inline friend void UnsignedAdd(int2048 &, const int2048 *); + inline friend void UnsignedMinus(int2048 &, const int2048 *); + int2048 &add(const int2048 &); + friend int2048 add(int2048, const int2048 &); + + int2048 &minus(const int2048 &); + friend int2048 minus(int2048, const int2048 &); + + int2048 operator+() const; + int2048 operator-() const; + + int2048 &operator=(const int2048 &); + int2048 &operator=(int2048 &&) noexcept; + + int2048 &operator+=(const int2048 &); + friend int2048 operator+(int2048, const int2048 &); + + int2048 &operator-=(const int2048 &); + friend int2048 operator-(int2048, const int2048 &); + + inline friend void UnsignedMultiply(int2048 &, const int2048 *); + int2048 &Multiply(const int2048 &); + friend int2048 Multiply(int2048, const int2048 &); + + int2048 &operator*=(const int2048 &); + friend int2048 operator*(int2048, const int2048 &); + + inline friend void UnsignedDivide(int2048 &, const int2048 *); + int2048 &Divide(const int2048 &); + friend int2048 Divide(int2048, const int2048 &); + + /** + * If the denominator is zero, the result is undefined. + * But actually it will return 0 with no exception thrown. + * And % operation is also based on this rule. + */ + int2048 &operator/=(const int2048 &); + friend int2048 operator/(int2048, const int2048 &); + + int2048 &operator%=(const int2048 &); + friend int2048 operator%(int2048, const int2048 &); + + friend std::istream &operator>>(std::istream &, int2048 &); + friend std::ostream &operator<<(std::ostream &, const int2048 &); + + friend bool operator==(const int2048 &, const int2048 &); + friend bool operator!=(const int2048 &, const int2048 &); + friend bool operator<(const int2048 &, const int2048 &); + friend bool operator>(const int2048 &, const int2048 &); + friend bool operator<=(const int2048 &, const int2048 &); + friend bool operator>=(const int2048 &, const int2048 &); +}; +} // namespace sjtu + +#endif \ No newline at end of file diff --git a/libs/json/json.hpp b/libs/json/json.hpp new file mode 100644 index 0000000..4d1a37a --- /dev/null +++ b/libs/json/json.hpp @@ -0,0 +1,24596 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #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) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// 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); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.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__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(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) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __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__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(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) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#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 + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// 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 +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get 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 +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template