From a6013437b292323d5085e3f6b1d97310ab35b293 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 22 Aug 2021 19:03:03 +0200 Subject: [PATCH] Initial commit. --- .clang-format | 124 + .clang-tidy | 11 + .gitignore | 3 + .gitmodules | 3 + CMakeLists.txt | 21 + CMakeLists.txt.in | 52 + extern/args.hpp | 4310 ++++++ extern/json.hpp | 22875 +++++++++++++++++++++++++++++++ src/BuildData | 1 + src/Precompiled.hxx | 6 + src/Tester/AssertionFailed.hpp | 48 + src/Tester/Test.hpp | 40 + src/Tester/TestEnvironment.hpp | 8 + src/Tester/TestFunctions.hpp | 61 + src/Tester/TestResult.hpp | 6 + src/Tester/TestRunner.hpp | 42 + src/main.cpp | 56 + 17 files changed, 27667 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 CMakeLists.txt.in create mode 100644 extern/args.hpp create mode 100644 extern/json.hpp create mode 160000 src/BuildData create mode 100644 src/Precompiled.hxx create mode 100644 src/Tester/AssertionFailed.hpp create mode 100644 src/Tester/Test.hpp create mode 100644 src/Tester/TestEnvironment.hpp create mode 100644 src/Tester/TestFunctions.hpp create mode 100644 src/Tester/TestResult.hpp create mode 100644 src/Tester/TestRunner.hpp create mode 100644 src/main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..658d238 --- /dev/null +++ b/.clang-format @@ -0,0 +1,124 @@ +# ClangFormatConfigureSource: 'LLVM' +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Merge +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 1 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION + - Ensure + - EnsureNotNull + - Try +TabWidth: 8 +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..ff1f909 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,11 @@ +Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*,cppcoreguidelines-*, +bugprone-*,modernize-*,-modernize-use-trailing-return-type,-cppcoreguidelines-non-private-member-variables-in-classes' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +CheckOptions: + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.PrivateMemberCase + value: camelBack + - key: readability-identifier-naming.PrivateMemberPrefix + value: '_' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27e4eed --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/cmake-build-debug/ +/cmake-build-release/ +/.idea/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3242d06 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/BuildData"] + path = src/BuildData + url = git@ssh.p-epsilon.com:Deukhoofd/BuildData.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2b3dc4d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.20) +project(PokemonScriptTester) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") + + +option(WINDOWS "Whether the build target is Windows or not." OFF) +set(STATICC TRUE) + +include(CMakeLists.txt.in) +include_pkmnlib() + +file(GLOB_RECURSE SRC_FILES src/*.cpp src/*.hpp) +add_executable(PokemonScriptTester ${SRC_FILES}) +target_precompile_headers(PokemonScriptTester PUBLIC src/Precompiled.hxx) +add_definitions(-DLEVEL_U8) + +SET(_LINKS Arbutils CreatureLib pkmnLib -lpthread) +target_link_libraries(PokemonScriptTester PUBLIC ${_LINKS}) +target_compile_options(PokemonScriptTester PRIVATE -Wall -Wextra -Werror) diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in new file mode 100644 index 0000000..10aca87 --- /dev/null +++ b/CMakeLists.txt.in @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(PokemonScriptTester NONE) + +include(ExternalProject) +ExternalProject_Add(pkmnlib + GIT_REPOSITORY https://git.p-epsilon.com/Deukhoofd/PkmnLib + GIT_TAG master + PREFIX "${CMAKE_CURRENT_BINARY_DIR}/PkmnLib" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + CMAKE_ARGS "-DSHARED=${SHARED} -DWINDOWS=${WINDOWS} -DSTATICC=${STATICC}" + ) + + +function(include_pkmnlib) + # Download and unpack googletest at configure time + configure_file(CMakeLists.txt.in PkmnLib/download/CMakeLists.txt) + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/download) + if (result) + message(FATAL_ERROR "CMake step for pkmnlib failed: ${result}") + endif () + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/download) + if (result) + message(FATAL_ERROR "Build step for pkmnlib failed: ${result}") + endif () + + # Add googletest directly to our build. This defines + # the gtest and gtest_main targets. + add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/src/pkmnlib + ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin + EXCLUDE_FROM_ALL) + + execute_process(COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include) + execute_process(COMMAND ln -s ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/src/pkmnlib/src + ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include/PkmnLib) + execute_process(COMMAND cp -r ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/src/pkmnlib/extern + ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include/PkmnLib/extern) + + include_directories(${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/include + ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin/CreatureLib/include + ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin/Angelscript/src/AngelscriptProj/angelscript/include + ${CMAKE_CURRENT_BINARY_DIR}/PkmnLib/bin/CreatureLib/bin/Arbutils/include) + + +endfunction() \ No newline at end of file diff --git a/extern/args.hpp b/extern/args.hpp new file mode 100644 index 0000000..717fd68 --- /dev/null +++ b/extern/args.hpp @@ -0,0 +1,4310 @@ +/* A simple header-only C++ argument parser library. + * + * https://github.com/Taywee/args + * + * Copyright (c) 2016-2020 Taylor C. Richberger and Pavel + * Belikov + * + * 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. + */ + +/** \file args.hxx + * \brief this single-header lets you use all of the args functionality + * + * The important stuff is done inside the args namespace + */ + +#ifndef ARGS_HXX +#define ARGS_HXX + +#define ARGS_VERSION "6.2.3" +#define ARGS_VERSION_MAJOR 6 +#define ARGS_VERSION_MINOR 2 +#define ARGS_VERSION_PATCH 3 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +#define noexcept +#endif + +#ifdef ARGS_TESTNAMESPACE +namespace argstest +{ +#else + +/** \namespace args + * \brief contains all the functionality of the args library + */ +namespace args +{ +#endif + /** Getter to grab the value from the argument type. + * + * If the Get() function of the type returns a reference, so does this, and + * the value will be modifiable. + */ + template + auto get(Option &option_) -> decltype(option_.Get()) + { + return option_.Get(); + } + + /** (INTERNAL) Count UTF-8 glyphs + * + * This is not reliable, and will fail for combinatory glyphs, but it's + * good enough here for now. + * + * \param string The string to count glyphs from + * \return The UTF-8 glyphs in the string + */ + inline std::string::size_type Glyphs(const std::string &string_) + { + std::string::size_type length = 0; + for (const char c: string_) + { + if ((c & 0xc0) != 0x80) + { + ++length; + } + } + return length; + } + + /** (INTERNAL) Wrap a vector of words into a vector of lines + * + * Empty words are skipped. Word "\n" forces wrapping. + * + * \param begin The begin iterator + * \param end The end iterator + * \param width The width of the body + * \param firstlinewidth the width of the first line, defaults to the width of the body + * \param firstlineindent the indent of the first line, defaults to 0 + * \return the vector of lines + */ + template + inline std::vector Wrap(It begin, + It end, + const std::string::size_type width, + std::string::size_type firstlinewidth = 0, + std::string::size_type firstlineindent = 0) + { + std::vector output; + std::string line(firstlineindent, ' '); + bool empty = true; + + if (firstlinewidth == 0) + { + firstlinewidth = width; + } + + auto currentwidth = firstlinewidth; + + for (auto it = begin; it != end; ++it) + { + if (it->empty()) + { + continue; + } + + if (*it == "\n") + { + if (!empty) + { + output.push_back(line); + line.clear(); + empty = true; + currentwidth = width; + } + + continue; + } + + auto itemsize = Glyphs(*it); + if ((line.length() + 1 + itemsize) > currentwidth) + { + if (!empty) + { + output.push_back(line); + line.clear(); + empty = true; + currentwidth = width; + } + } + + if (itemsize > 0) + { + if (!empty) + { + line += ' '; + } + + line += *it; + empty = false; + } + } + + if (!empty) + { + output.push_back(line); + } + + return output; + } + + namespace detail + { + template + std::string Join(const T& array, const std::string &delimiter) + { + std::string res; + for (auto &element : array) + { + if (!res.empty()) + { + res += delimiter; + } + + res += element; + } + + return res; + } + } + + /** (INTERNAL) Wrap a string into a vector of lines + * + * This is quick and hacky, but works well enough. You can specify a + * different width for the first line + * + * \param width The width of the body + * \param firstlinewid the width of the first line, defaults to the width of the body + * \return the vector of lines + */ + inline std::vector Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth = 0) + { + // Preserve existing line breaks + const auto newlineloc = in.find('\n'); + if (newlineloc != in.npos) + { + auto first = Wrap(std::string(in, 0, newlineloc), width); + auto second = Wrap(std::string(in, newlineloc + 1), width); + first.insert( + std::end(first), + std::make_move_iterator(std::begin(second)), + std::make_move_iterator(std::end(second))); + return first; + } + + std::istringstream stream(in); + std::string::size_type indent = 0; + + for (char c : in) + { + if (!isspace(c)) + { + break; + } + ++indent; + } + + return Wrap(std::istream_iterator(stream), std::istream_iterator(), + width, firstlinewidth, indent); + } + +#ifdef ARGS_NOEXCEPT + /// Error class, for when ARGS_NOEXCEPT is defined + enum class Error + { + None, + Usage, + Parse, + Validation, + Required, + Map, + Extra, + Help, + Subparser, + Completion, + }; +#else + /** Base error class + */ + class Error : public std::runtime_error + { + public: + Error(const std::string &problem) : std::runtime_error(problem) {} + virtual ~Error() {} + }; + + /** Errors that occur during usage + */ + class UsageError : public Error + { + public: + UsageError(const std::string &problem) : Error(problem) {} + virtual ~UsageError() {} + }; + + /** Errors that occur during regular parsing + */ + class ParseError : public Error + { + public: + ParseError(const std::string &problem) : Error(problem) {} + virtual ~ParseError() {} + }; + + /** Errors that are detected from group validation after parsing finishes + */ + class ValidationError : public Error + { + public: + ValidationError(const std::string &problem) : Error(problem) {} + virtual ~ValidationError() {} + }; + + /** Errors that when a required flag is omitted + */ + class RequiredError : public ValidationError + { + public: + RequiredError(const std::string &problem) : ValidationError(problem) {} + virtual ~RequiredError() {} + }; + + /** Errors in map lookups + */ + class MapError : public ParseError + { + public: + MapError(const std::string &problem) : ParseError(problem) {} + virtual ~MapError() {} + }; + + /** Error that occurs when a singular flag is specified multiple times + */ + class ExtraError : public ParseError + { + public: + ExtraError(const std::string &problem) : ParseError(problem) {} + virtual ~ExtraError() {} + }; + + /** An exception that indicates that the user has requested help + */ + class Help : public Error + { + public: + Help(const std::string &flag) : Error(flag) {} + virtual ~Help() {} + }; + + /** (INTERNAL) An exception that emulates coroutine-like control flow for subparsers. + */ + class SubparserError : public Error + { + public: + SubparserError() : Error("") {} + virtual ~SubparserError() {} + }; + + /** An exception that contains autocompletion reply + */ + class Completion : public Error + { + public: + Completion(const std::string &flag) : Error(flag) {} + virtual ~Completion() {} + }; +#endif + + /** A simple unified option type for unified initializer lists for the Matcher class. + */ + struct EitherFlag + { + const bool isShort; + const char shortFlag; + const std::string longFlag; + EitherFlag(const std::string &flag) : isShort(false), shortFlag(), longFlag(flag) {} + EitherFlag(const char *flag) : isShort(false), shortFlag(), longFlag(flag) {} + EitherFlag(const char flag) : isShort(true), shortFlag(flag), longFlag() {} + + /** Get just the long flags from an initializer list of EitherFlags + */ + static std::unordered_set GetLong(std::initializer_list flags) + { + std::unordered_set longFlags; + for (const EitherFlag &flag: flags) + { + if (!flag.isShort) + { + longFlags.insert(flag.longFlag); + } + } + return longFlags; + } + + /** Get just the short flags from an initializer list of EitherFlags + */ + static std::unordered_set GetShort(std::initializer_list flags) + { + std::unordered_set shortFlags; + for (const EitherFlag &flag: flags) + { + if (flag.isShort) + { + shortFlags.insert(flag.shortFlag); + } + } + return shortFlags; + } + + std::string str() const + { + return isShort ? std::string(1, shortFlag) : longFlag; + } + + std::string str(const std::string &shortPrefix, const std::string &longPrefix) const + { + return isShort ? shortPrefix + std::string(1, shortFlag) : longPrefix + longFlag; + } + }; + + + + /** A class of "matchers", specifying short and flags that can possibly be + * matched. + * + * This is supposed to be constructed and then passed in, not used directly + * from user code. + */ + class Matcher + { + private: + const std::unordered_set shortFlags; + const std::unordered_set longFlags; + + public: + /** Specify short and long flags separately as iterators + * + * ex: `args::Matcher(shortFlags.begin(), shortFlags.end(), longFlags.begin(), longFlags.end())` + */ + template + Matcher(ShortIt shortFlagsStart, ShortIt shortFlagsEnd, LongIt longFlagsStart, LongIt longFlagsEnd) : + shortFlags(shortFlagsStart, shortFlagsEnd), + longFlags(longFlagsStart, longFlagsEnd) + { + if (shortFlags.empty() && longFlags.empty()) + { +#ifndef ARGS_NOEXCEPT + throw UsageError("empty Matcher"); +#endif + } + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + Error GetError() const noexcept + { + return shortFlags.empty() && longFlags.empty() ? Error::Usage : Error::None; + } +#endif + + /** Specify short and long flags separately as iterables + * + * ex: `args::Matcher(shortFlags, longFlags)` + */ + template + Matcher(Short &&shortIn, Long &&longIn) : + Matcher(std::begin(shortIn), std::end(shortIn), std::begin(longIn), std::end(longIn)) + {} + + /** Specify a mixed single initializer-list of both short and long flags + * + * This is the fancy one. It takes a single initializer list of + * any number of any mixed kinds of flags. Chars are + * automatically interpreted as short flags, and strings are + * automatically interpreted as long flags: + * + * args::Matcher{'a'} + * args::Matcher{"foo"} + * args::Matcher{'h', "help"} + * args::Matcher{"foo", 'f', 'F', "FoO"} + */ + Matcher(std::initializer_list in) : + Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {} + + Matcher(Matcher &&other) : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags)) + {} + + ~Matcher() {} + + /** (INTERNAL) Check if there is a match of a short flag + */ + bool Match(const char flag) const + { + return shortFlags.find(flag) != shortFlags.end(); + } + + /** (INTERNAL) Check if there is a match of a long flag + */ + bool Match(const std::string &flag) const + { + return longFlags.find(flag) != longFlags.end(); + } + + /** (INTERNAL) Check if there is a match of a flag + */ + bool Match(const EitherFlag &flag) const + { + return flag.isShort ? Match(flag.shortFlag) : Match(flag.longFlag); + } + + /** (INTERNAL) Get all flag strings as a vector, with the prefixes embedded + */ + std::vector GetFlagStrings() const + { + std::vector flagStrings; + flagStrings.reserve(shortFlags.size() + longFlags.size()); + for (const char flag: shortFlags) + { + flagStrings.emplace_back(flag); + } + for (const std::string &flag: longFlags) + { + flagStrings.emplace_back(flag); + } + return flagStrings; + } + + /** (INTERNAL) Get long flag if it exists or any short flag + */ + EitherFlag GetLongOrAny() const + { + if (!longFlags.empty()) + { + return *longFlags.begin(); + } + + if (!shortFlags.empty()) + { + return *shortFlags.begin(); + } + + // should be unreachable + return ' '; + } + + /** (INTERNAL) Get short flag if it exists or any long flag + */ + EitherFlag GetShortOrAny() const + { + if (!shortFlags.empty()) + { + return *shortFlags.begin(); + } + + if (!longFlags.empty()) + { + return *longFlags.begin(); + } + + // should be unreachable + return ' '; + } + }; + + /** Attributes for flags. + */ + enum class Options + { + /** Default options. + */ + None = 0x0, + + /** Flag can't be passed multiple times. + */ + Single = 0x01, + + /** Flag can't be omitted. + */ + Required = 0x02, + + /** Flag is excluded from usage line. + */ + HiddenFromUsage = 0x04, + + /** Flag is excluded from options help. + */ + HiddenFromDescription = 0x08, + + /** Flag is global and can be used in any subcommand. + */ + Global = 0x10, + + /** Flag stops a parser. + */ + KickOut = 0x20, + + /** Flag is excluded from auto completion. + */ + HiddenFromCompletion = 0x40, + + /** Flag is excluded from options help and usage line + */ + Hidden = HiddenFromUsage | HiddenFromDescription | HiddenFromCompletion, + }; + + inline Options operator | (Options lhs, Options rhs) + { + return static_cast(static_cast(lhs) | static_cast(rhs)); + } + + inline Options operator & (Options lhs, Options rhs) + { + return static_cast(static_cast(lhs) & static_cast(rhs)); + } + + class FlagBase; + class PositionalBase; + class Command; + class ArgumentParser; + + /** A simple structure of parameters for easy user-modifyable help menus + */ + struct HelpParams + { + /** The width of the help menu + */ + unsigned int width = 80; + /** The indent of the program line + */ + unsigned int progindent = 2; + /** The indent of the program trailing lines for long parameters + */ + unsigned int progtailindent = 4; + /** The indent of the description and epilogs + */ + unsigned int descriptionindent = 4; + /** The indent of the flags + */ + unsigned int flagindent = 6; + /** The indent of the flag descriptions + */ + unsigned int helpindent = 40; + /** The additional indent each group adds + */ + unsigned int eachgroupindent = 2; + + /** The minimum gutter between each flag and its help + */ + unsigned int gutter = 1; + + /** Show the terminator when both options and positional parameters are present + */ + bool showTerminator = true; + + /** Show the {OPTIONS} on the prog line when this is true + */ + bool showProglineOptions = true; + + /** Show the positionals on the prog line when this is true + */ + bool showProglinePositionals = true; + + /** The prefix for short flags + */ + std::string shortPrefix; + + /** The prefix for long flags + */ + std::string longPrefix; + + /** The separator for short flags + */ + std::string shortSeparator; + + /** The separator for long flags + */ + std::string longSeparator; + + /** The program name for help generation + */ + std::string programName; + + /** Show command's flags + */ + bool showCommandChildren = false; + + /** Show command's descriptions and epilog + */ + bool showCommandFullHelp = false; + + /** The postfix for progline when showProglineOptions is true and command has any flags + */ + std::string proglineOptions = "{OPTIONS}"; + + /** The prefix for progline when command has any subcommands + */ + std::string proglineCommand = "COMMAND"; + + /** The prefix for progline value + */ + std::string proglineValueOpen = " <"; + + /** The postfix for progline value + */ + std::string proglineValueClose = ">"; + + /** The prefix for progline required argument + */ + std::string proglineRequiredOpen = ""; + + /** The postfix for progline required argument + */ + std::string proglineRequiredClose = ""; + + /** The prefix for progline non-required argument + */ + std::string proglineNonrequiredOpen = "["; + + /** The postfix for progline non-required argument + */ + std::string proglineNonrequiredClose = "]"; + + /** Show flags in program line + */ + bool proglineShowFlags = false; + + /** Use short flags in program lines when possible + */ + bool proglinePreferShortFlags = false; + + /** Program line prefix + */ + std::string usageString; + + /** String shown in help before flags descriptions + */ + std::string optionsString = "OPTIONS:"; + + /** Display value name after all the long and short flags + */ + bool useValueNameOnce = false; + + /** Show value name + */ + bool showValueName = true; + + /** Add newline before flag description + */ + bool addNewlineBeforeDescription = false; + + /** The prefix for option value + */ + std::string valueOpen = "["; + + /** The postfix for option value + */ + std::string valueClose = "]"; + + /** Add choices to argument description + */ + bool addChoices = false; + + /** The prefix for choices + */ + std::string choiceString = "\nOne of: "; + + /** Add default values to argument description + */ + bool addDefault = false; + + /** The prefix for default values + */ + std::string defaultString = "\nDefault: "; + }; + + /** A number of arguments which can be consumed by an option. + * + * Represents a closed interval [min, max]. + */ + struct Nargs + { + const size_t min; + const size_t max; + + Nargs(size_t min_, size_t max_) : min{min_}, max{max_} + { +#ifndef ARGS_NOEXCEPT + if (max < min) + { + throw UsageError("Nargs: max > min"); + } +#endif + } + + Nargs(size_t num_) : min{num_}, max{num_} + { + } + + friend bool operator == (const Nargs &lhs, const Nargs &rhs) + { + return lhs.min == rhs.min && lhs.max == rhs.max; + } + + friend bool operator != (const Nargs &lhs, const Nargs &rhs) + { + return !(lhs == rhs); + } + }; + + /** Base class for all match types + */ + class Base + { + private: + Options options = {}; + + protected: + bool matched = false; + const std::string help; +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + mutable Error error = Error::None; + mutable std::string errorMsg; +#endif + + public: + Base(const std::string &help_, Options options_ = {}) : options(options_), help(help_) {} + virtual ~Base() {} + + Options GetOptions() const noexcept + { + return options; + } + + bool IsRequired() const noexcept + { + return (GetOptions() & Options::Required) != Options::None; + } + + virtual bool Matched() const noexcept + { + return matched; + } + + virtual void Validate(const std::string &, const std::string &) const + { + } + + operator bool() const noexcept + { + return Matched(); + } + + virtual std::vector> GetDescription(const HelpParams &, const unsigned indentLevel) const + { + std::tuple description; + std::get<1>(description) = help; + std::get<2>(description) = indentLevel; + return { std::move(description) }; + } + + virtual std::vector GetCommands() + { + return {}; + } + + virtual bool IsGroup() const + { + return false; + } + + virtual FlagBase *Match(const EitherFlag &) + { + return nullptr; + } + + virtual PositionalBase *GetNextPositional() + { + return nullptr; + } + + virtual std::vector GetAllFlags() + { + return {}; + } + + virtual bool HasFlag() const + { + return false; + } + + virtual bool HasPositional() const + { + return false; + } + + virtual bool HasCommand() const + { + return false; + } + + virtual std::vector GetProgramLine(const HelpParams &) const + { + return {}; + } + + /// Sets a kick-out value for building subparsers + void KickOut(bool kickout_) noexcept + { + if (kickout_) + { + options = options | Options::KickOut; + } + else + { + options = static_cast(static_cast(options) & ~static_cast(Options::KickOut)); + } + } + + /// Gets the kick-out value for building subparsers + bool KickOut() const noexcept + { + return (options & Options::KickOut) != Options::None; + } + + virtual void Reset() noexcept + { + matched = false; +#ifdef ARGS_NOEXCEPT + error = Error::None; + errorMsg.clear(); +#endif + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const + { + return error; + } + + /// Only for ARGS_NOEXCEPT + std::string GetErrorMsg() const + { + return errorMsg; + } +#endif + }; + + /** Base class for all match types that have a name + */ + class NamedBase : public Base + { + protected: + const std::string name; + bool kickout = false; + std::string defaultString; + bool defaultStringManual = false; + std::vector choicesStrings; + bool choicesStringManual = false; + + virtual std::string GetDefaultString(const HelpParams&) const { return {}; } + + virtual std::vector GetChoicesStrings(const HelpParams&) const { return {}; } + + virtual std::string GetNameString(const HelpParams&) const { return Name(); } + + void AddDescriptionPostfix(std::string &dest, const bool isManual, const std::string &manual, bool isGenerated, const std::string &generated, const std::string &str) const + { + if (isManual && !manual.empty()) + { + dest += str; + dest += manual; + } + else if (!isManual && isGenerated && !generated.empty()) + { + dest += str; + dest += generated; + } + } + + public: + NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {} + virtual ~NamedBase() {} + + /** Sets default value string that will be added to argument description. + * Use empty string to disable it for this argument. + */ + void HelpDefault(const std::string &str) + { + defaultStringManual = true; + defaultString = str; + } + + /** Gets default value string that will be added to argument description. + */ + std::string HelpDefault(const HelpParams ¶ms) const + { + return defaultStringManual ? defaultString : GetDefaultString(params); + } + + /** Sets choices strings that will be added to argument description. + * Use empty vector to disable it for this argument. + */ + void HelpChoices(const std::vector &array) + { + choicesStringManual = true; + choicesStrings = array; + } + + /** Gets choices strings that will be added to argument description. + */ + std::vector HelpChoices(const HelpParams ¶ms) const + { + return choicesStringManual ? choicesStrings : GetChoicesStrings(params); + } + + virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned indentLevel) const override + { + std::tuple description; + std::get<0>(description) = GetNameString(params); + std::get<1>(description) = help; + std::get<2>(description) = indentLevel; + + AddDescriptionPostfix(std::get<1>(description), choicesStringManual, detail::Join(choicesStrings, ", "), params.addChoices, detail::Join(GetChoicesStrings(params), ", "), params.choiceString); + AddDescriptionPostfix(std::get<1>(description), defaultStringManual, defaultString, params.addDefault, GetDefaultString(params), params.defaultString); + + return { std::move(description) }; + } + + virtual std::string Name() const + { + return name; + } + }; + + namespace detail + { + template + using vector = std::vector>; + + template + using unordered_map = std::unordered_map, + std::equal_to, std::allocator > >; + + template + class is_streamable + { + template + static auto test(int) + -> decltype( std::declval() << std::declval(), std::true_type() ); + + template + static auto test(...) -> std::false_type; + + public: + using type = decltype(test(0)); + }; + + template + using IsConvertableToString = typename is_streamable::type; + + template + typename std::enable_if::value, std::string>::type + ToString(const T &value) + { + std::ostringstream s; + s << value; + return s.str(); + } + + template + typename std::enable_if::value, std::string>::type + ToString(const T &) + { + return {}; + } + + template + std::vector MapKeysToStrings(const T &map) + { + std::vector res; + using K = typename std::decayfirst)>::type; + if (IsConvertableToString::value) + { + for (const auto &p : map) + { + res.push_back(detail::ToString(p.first)); + } + + std::sort(res.begin(), res.end()); + } + return res; + } + } + + /** Base class for all flag options + */ + class FlagBase : public NamedBase + { + protected: + const Matcher matcher; + + virtual std::string GetNameString(const HelpParams ¶ms) const override + { + const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name(); + std::string flags; + const auto flagStrings = matcher.GetFlagStrings(); + const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce; + for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it) + { + auto &flag = *it; + if (it != flagStrings.begin()) + { + flags += ", "; + } + + flags += flag.isShort ? params.shortPrefix : params.longPrefix; + flags += flag.str(); + + if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end())) + { + flags += flag.isShort ? params.shortSeparator : params.longSeparator; + flags += params.valueOpen + postfix + params.valueClose; + } + } + + return flags; + } + + public: + FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : NamedBase(name_, help_, extraError_ ? Options::Single : Options()), matcher(std::move(matcher_)) {} + + FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : NamedBase(name_, help_, options_), matcher(std::move(matcher_)) {} + + virtual ~FlagBase() {} + + virtual FlagBase *Match(const EitherFlag &flag) override + { + if (matcher.Match(flag)) + { + if ((GetOptions() & Options::Single) != Options::None && matched) + { + std::ostringstream problem; + problem << "Flag '" << flag.str() << "' was passed multiple times, but is only allowed to be passed once"; +#ifdef ARGS_NOEXCEPT + error = Error::Extra; + errorMsg = problem.str(); +#else + throw ExtraError(problem.str()); +#endif + } + matched = true; + return this; + } + return nullptr; + } + + virtual std::vector GetAllFlags() override + { + return { this }; + } + + const Matcher &GetMatcher() const + { + return matcher; + } + + virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override + { + if (!Matched() && IsRequired()) + { + std::ostringstream problem; + problem << "Flag '" << matcher.GetLongOrAny().str(shortPrefix, longPrefix) << "' is required"; +#ifdef ARGS_NOEXCEPT + error = Error::Required; + errorMsg = problem.str(); +#else + throw RequiredError(problem.str()); +#endif + } + } + + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + if (!params.proglineShowFlags) + { + return {}; + } + + const std::string postfix = NumberOfArguments() == 0 ? std::string() : Name(); + const EitherFlag flag = params.proglinePreferShortFlags ? matcher.GetShortOrAny() : matcher.GetLongOrAny(); + std::string res = flag.str(params.shortPrefix, params.longPrefix); + if (!postfix.empty()) + { + res += params.proglineValueOpen + postfix + params.proglineValueClose; + } + + return { IsRequired() ? params.proglineRequiredOpen + res + params.proglineRequiredClose + : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose }; + } + + virtual bool HasFlag() const override + { + return true; + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const override + { + const auto nargs = NumberOfArguments(); + if (nargs.min > nargs.max) + { + return Error::Usage; + } + + const auto matcherError = matcher.GetError(); + if (matcherError != Error::None) + { + return matcherError; + } + + return error; + } +#endif + + /** Defines how many values can be consumed by this option. + * + * \return closed interval [min, max] + */ + virtual Nargs NumberOfArguments() const noexcept = 0; + + /** Parse values of this option. + * + * \param value Vector of values. It's size must be in NumberOfArguments() interval. + */ + virtual void ParseValue(const std::vector &value) = 0; + }; + + /** Base class for value-accepting flag options + */ + class ValueFlagBase : public FlagBase + { + public: + ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : FlagBase(name_, help_, std::move(matcher_), extraError_) {} + ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : FlagBase(name_, help_, std::move(matcher_), options_) {} + virtual ~ValueFlagBase() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return 1; + } + }; + + class CompletionFlag : public ValueFlagBase + { + public: + std::vector reply; + size_t cword = 0; + std::string syntax; + + template + CompletionFlag(GroupClass &group_, Matcher &&matcher_): ValueFlagBase("completion", "completion flag", std::move(matcher_), Options::Hidden) + { + group_.AddCompletion(*this); + } + + virtual ~CompletionFlag() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return 2; + } + + virtual void ParseValue(const std::vector &value_) override + { + syntax = value_.at(0); + std::istringstream(value_.at(1)) >> cword; + } + + /** Get the completion reply + */ + std::string Get() noexcept + { + return detail::Join(reply, "\n"); + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + cword = 0; + syntax.clear(); + reply.clear(); + } + }; + + + /** Base class for positional options + */ + class PositionalBase : public NamedBase + { + protected: + bool ready; + + public: + PositionalBase(const std::string &name_, const std::string &help_, Options options_ = {}) : NamedBase(name_, help_, options_), ready(true) {} + virtual ~PositionalBase() {} + + bool Ready() + { + return ready; + } + + virtual void ParseValue(const std::string &value_) = 0; + + virtual void Reset() noexcept override + { + matched = false; + ready = true; +#ifdef ARGS_NOEXCEPT + error = Error::None; + errorMsg.clear(); +#endif + } + + virtual PositionalBase *GetNextPositional() override + { + return Ready() ? this : nullptr; + } + + virtual bool HasPositional() const override + { + return true; + } + + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + return { IsRequired() ? params.proglineRequiredOpen + Name() + params.proglineRequiredClose + : params.proglineNonrequiredOpen + Name() + params.proglineNonrequiredClose }; + } + + virtual void Validate(const std::string &, const std::string &) const override + { + if (IsRequired() && !Matched()) + { + std::ostringstream problem; + problem << "Option '" << Name() << "' is required"; +#ifdef ARGS_NOEXCEPT + error = Error::Required; + errorMsg = problem.str(); +#else + throw RequiredError(problem.str()); +#endif + } + } + }; + + /** Class for all kinds of validating groups, including ArgumentParser + */ + class Group : public Base + { + private: + std::vector children; + std::function validator; + + public: + /** Default validators + */ + struct Validators + { + static bool Xor(const Group &group) + { + return group.MatchedChildren() == 1; + } + + static bool AtLeastOne(const Group &group) + { + return group.MatchedChildren() >= 1; + } + + static bool AtMostOne(const Group &group) + { + return group.MatchedChildren() <= 1; + } + + static bool All(const Group &group) + { + return group.Children().size() == group.MatchedChildren(); + } + + static bool AllOrNone(const Group &group) + { + return (All(group) || None(group)); + } + + static bool AllChildGroups(const Group &group) + { + return std::none_of(std::begin(group.Children()), std::end(group.Children()), [](const Base* child) -> bool { + return child->IsGroup() && !child->Matched(); + }); + } + + static bool DontCare(const Group &) + { + return true; + } + + static bool CareTooMuch(const Group &) + { + return false; + } + + static bool None(const Group &group) + { + return group.MatchedChildren() == 0; + } + }; + /// If help is empty, this group will not be printed in help output + Group(const std::string &help_ = std::string(), const std::function &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_) {} + /// If help is empty, this group will not be printed in help output + Group(Group &group_, const std::string &help_ = std::string(), const std::function &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_) + { + group_.Add(*this); + } + virtual ~Group() {} + + /** Append a child to this Group. + */ + void Add(Base &child) + { + children.emplace_back(&child); + } + + /** Get all this group's children + */ + const std::vector &Children() const + { + return children; + } + + /** Return the first FlagBase that matches flag, or nullptr + * + * \param flag The flag with prefixes stripped + * \return the first matching FlagBase pointer, or nullptr if there is no match + */ + virtual FlagBase *Match(const EitherFlag &flag) override + { + for (Base *child: Children()) + { + if (FlagBase *match = child->Match(flag)) + { + return match; + } + } + return nullptr; + } + + virtual std::vector GetAllFlags() override + { + std::vector res; + for (Base *child: Children()) + { + auto childRes = child->GetAllFlags(); + res.insert(res.end(), childRes.begin(), childRes.end()); + } + return res; + } + + virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override + { + for (Base *child: Children()) + { + child->Validate(shortPrefix, longPrefix); + } + } + + /** Get the next ready positional, or nullptr if there is none + * + * \return the first ready PositionalBase pointer, or nullptr if there is no match + */ + virtual PositionalBase *GetNextPositional() override + { + for (Base *child: Children()) + { + if (auto next = child->GetNextPositional()) + { + return next; + } + } + return nullptr; + } + + /** Get whether this has any FlagBase children + * + * \return Whether or not there are any FlagBase children + */ + virtual bool HasFlag() const override + { + return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasFlag(); }); + } + + /** Get whether this has any PositionalBase children + * + * \return Whether or not there are any PositionalBase children + */ + virtual bool HasPositional() const override + { + return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasPositional(); }); + } + + /** Get whether this has any Command children + * + * \return Whether or not there are any Command children + */ + virtual bool HasCommand() const override + { + return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasCommand(); }); + } + + /** Count the number of matched children this group has + */ + std::vector::size_type MatchedChildren() const + { + // Cast to avoid warnings from -Wsign-conversion + return static_cast::size_type>( + std::count_if(std::begin(Children()), std::end(Children()), [](const Base *child){return child->Matched();})); + } + + /** Whether or not this group matches validation + */ + virtual bool Matched() const noexcept override + { + return validator(*this); + } + + /** Get validation + */ + bool Get() const + { + return Matched(); + } + + /** Get all the child descriptions for help generation + */ + virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned int indent) const override + { + std::vector> descriptions; + + // Push that group description on the back if not empty + unsigned addindent = 0; + if (!help.empty()) + { + descriptions.emplace_back(help, "", indent); + addindent = 1; + } + + for (Base *child: Children()) + { + if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None) + { + continue; + } + + auto groupDescriptions = child->GetDescription(params, indent + addindent); + descriptions.insert( + std::end(descriptions), + std::make_move_iterator(std::begin(groupDescriptions)), + std::make_move_iterator(std::end(groupDescriptions))); + } + return descriptions; + } + + /** Get the names of positional parameters + */ + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + std::vector names; + for (Base *child: Children()) + { + if ((child->GetOptions() & Options::HiddenFromUsage) != Options::None) + { + continue; + } + + auto groupNames = child->GetProgramLine(params); + names.insert( + std::end(names), + std::make_move_iterator(std::begin(groupNames)), + std::make_move_iterator(std::end(groupNames))); + } + return names; + } + + virtual std::vector GetCommands() override + { + std::vector res; + for (const auto &child : Children()) + { + auto subparsers = child->GetCommands(); + res.insert(std::end(res), std::begin(subparsers), std::end(subparsers)); + } + return res; + } + + virtual bool IsGroup() const override + { + return true; + } + + virtual void Reset() noexcept override + { + Base::Reset(); + + for (auto &child: Children()) + { + child->Reset(); + } +#ifdef ARGS_NOEXCEPT + error = Error::None; + errorMsg.clear(); +#endif + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const override + { + if (error != Error::None) + { + return error; + } + + auto it = std::find_if(Children().begin(), Children().end(), [](const Base *child){return child->GetError() != Error::None;}); + if (it == Children().end()) + { + return Error::None; + } else + { + return (*it)->GetError(); + } + } +#endif + + }; + + /** Class for using global options in ArgumentParser. + */ + class GlobalOptions : public Group + { + public: + GlobalOptions(Group &base, Base &options_) : Group(base, {}, Group::Validators::DontCare, Options::Global) + { + Add(options_); + } + }; + + /** Utility class for building subparsers with coroutines/callbacks. + * + * Brief example: + * \code + * Command command(argumentParser, "command", "my command", [](args::Subparser &s) + * { + * // your command flags/positionals + * s.Parse(); //required + * //your command code + * }); + * \endcode + * + * For ARGS_NOEXCEPT mode don't forget to check `s.GetError()` after `s.Parse()` + * and return if it isn't equals to args::Error::None. + * + * \sa Command + */ + class Subparser : public Group + { + private: + std::vector args; + std::vector kicked; + ArgumentParser *parser = nullptr; + const HelpParams &helpParams; + const Command &command; + bool isParsed = false; + + public: + Subparser(std::vector args_, ArgumentParser &parser_, const Command &command_, const HelpParams &helpParams_) + : Group({}, Validators::AllChildGroups), args(std::move(args_)), parser(&parser_), helpParams(helpParams_), command(command_) + { + } + + Subparser(const Command &command_, const HelpParams &helpParams_) : Group({}, Validators::AllChildGroups), helpParams(helpParams_), command(command_) + { + } + + Subparser(const Subparser&) = delete; + Subparser(Subparser&&) = delete; + Subparser &operator = (const Subparser&) = delete; + Subparser &operator = (Subparser&&) = delete; + + const Command &GetCommand() + { + return command; + } + + /** (INTERNAL) Determines whether Parse was called or not. + */ + bool IsParsed() const + { + return isParsed; + } + + /** Continue parsing arguments for new command. + */ + void Parse(); + + /** Returns a vector of kicked out arguments. + * + * \sa Base::KickOut + */ + const std::vector &KickedOut() const noexcept + { + return kicked; + } + }; + + /** Main class for building subparsers. + * + * /sa Subparser + */ + class Command : public Group + { + private: + friend class Subparser; + + std::string name; + std::string help; + std::string description; + std::string epilog; + std::string proglinePostfix; + + std::function parserCoroutine; + bool commandIsRequired = true; + Command *selectedCommand = nullptr; + + mutable std::vector> subparserDescription; + mutable std::vector subparserProgramLine; + mutable bool subparserHasFlag = false; + mutable bool subparserHasPositional = false; + mutable bool subparserHasCommand = false; +#ifdef ARGS_NOEXCEPT + mutable Error subparserError = Error::None; +#endif + mutable Subparser *subparser = nullptr; + + protected: + + class RaiiSubparser + { + public: + RaiiSubparser(ArgumentParser &parser_, std::vector args_); + RaiiSubparser(const Command &command_, const HelpParams ¶ms_); + + ~RaiiSubparser() + { + command.subparser = oldSubparser; + } + + Subparser &Parser() + { + return parser; + } + + private: + const Command &command; + Subparser parser; + Subparser *oldSubparser; + }; + + Command() = default; + + std::function &GetCoroutine() + { + return selectedCommand != nullptr ? selectedCommand->GetCoroutine() : parserCoroutine; + } + + Command &SelectedCommand() + { + Command *res = this; + while (res->selectedCommand != nullptr) + { + res = res->selectedCommand; + } + + return *res; + } + + const Command &SelectedCommand() const + { + const Command *res = this; + while (res->selectedCommand != nullptr) + { + res = res->selectedCommand; + } + + return *res; + } + + void UpdateSubparserHelp(const HelpParams ¶ms) const + { + if (parserCoroutine) + { + RaiiSubparser coro(*this, params); +#ifndef ARGS_NOEXCEPT + try + { + parserCoroutine(coro.Parser()); + } + catch (args::SubparserError&) + { + } +#else + parserCoroutine(coro.Parser()); +#endif + } + } + + public: + Command(Group &base_, std::string name_, std::string help_, std::function coroutine_ = {}) + : name(std::move(name_)), help(std::move(help_)), parserCoroutine(std::move(coroutine_)) + { + base_.Add(*this); + } + + /** The description that appears on the prog line after options + */ + const std::string &ProglinePostfix() const + { return proglinePostfix; } + + /** The description that appears on the prog line after options + */ + void ProglinePostfix(const std::string &proglinePostfix_) + { this->proglinePostfix = proglinePostfix_; } + + /** The description that appears above options + */ + const std::string &Description() const + { return description; } + /** The description that appears above options + */ + + void Description(const std::string &description_) + { this->description = description_; } + + /** The description that appears below options + */ + const std::string &Epilog() const + { return epilog; } + + /** The description that appears below options + */ + void Epilog(const std::string &epilog_) + { this->epilog = epilog_; } + + /** The name of command + */ + const std::string &Name() const + { return name; } + + /** The description of command + */ + const std::string &Help() const + { return help; } + + /** If value is true, parser will fail if no command was parsed. + * + * Default: true. + */ + void RequireCommand(bool value) + { commandIsRequired = value; } + + virtual bool IsGroup() const override + { return false; } + + virtual bool Matched() const noexcept override + { return Base::Matched(); } + + operator bool() const noexcept + { return Matched(); } + + void Match() noexcept + { matched = true; } + + void SelectCommand(Command *c) noexcept + { + selectedCommand = c; + + if (c != nullptr) + { + c->Match(); + } + } + + virtual FlagBase *Match(const EitherFlag &flag) override + { + if (selectedCommand != nullptr) + { + if (auto *res = selectedCommand->Match(flag)) + { + return res; + } + + for (auto *child: Children()) + { + if ((child->GetOptions() & Options::Global) != Options::None) + { + if (auto *res = child->Match(flag)) + { + return res; + } + } + } + + return nullptr; + } + + if (subparser != nullptr) + { + return subparser->Match(flag); + } + + return Matched() ? Group::Match(flag) : nullptr; + } + + virtual std::vector GetAllFlags() override + { + std::vector res; + + if (!Matched()) + { + return res; + } + + for (auto *child: Children()) + { + if (selectedCommand == nullptr || (child->GetOptions() & Options::Global) != Options::None) + { + auto childFlags = child->GetAllFlags(); + res.insert(res.end(), childFlags.begin(), childFlags.end()); + } + } + + if (selectedCommand != nullptr) + { + auto childFlags = selectedCommand->GetAllFlags(); + res.insert(res.end(), childFlags.begin(), childFlags.end()); + } + + if (subparser != nullptr) + { + auto childFlags = subparser->GetAllFlags(); + res.insert(res.end(), childFlags.begin(), childFlags.end()); + } + + return res; + } + + virtual PositionalBase *GetNextPositional() override + { + if (selectedCommand != nullptr) + { + if (auto *res = selectedCommand->GetNextPositional()) + { + return res; + } + + for (auto *child: Children()) + { + if ((child->GetOptions() & Options::Global) != Options::None) + { + if (auto *res = child->GetNextPositional()) + { + return res; + } + } + } + + return nullptr; + } + + if (subparser != nullptr) + { + return subparser->GetNextPositional(); + } + + return Matched() ? Group::GetNextPositional() : nullptr; + } + + virtual bool HasFlag() const override + { + return subparserHasFlag || Group::HasFlag(); + } + + virtual bool HasPositional() const override + { + return subparserHasPositional || Group::HasPositional(); + } + + virtual bool HasCommand() const override + { + return true; + } + + std::vector GetCommandProgramLine(const HelpParams ¶ms) const + { + UpdateSubparserHelp(params); + + auto res = Group::GetProgramLine(params); + res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end()); + + if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand)) + { + res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]"); + } + + if (!Name().empty()) + { + res.insert(res.begin(), Name()); + } + + if ((subparserHasFlag || Group::HasFlag()) && params.showProglineOptions && !params.proglineShowFlags) + { + res.push_back(params.proglineOptions); + } + + if (!ProglinePostfix().empty()) + { + std::string line; + for (char c : ProglinePostfix()) + { + if (isspace(c)) + { + if (!line.empty()) + { + res.push_back(line); + line.clear(); + } + + if (c == '\n') + { + res.push_back("\n"); + } + } + else + { + line += c; + } + } + + if (!line.empty()) + { + res.push_back(line); + } + } + + return res; + } + + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + if (!Matched()) + { + return {}; + } + + return GetCommandProgramLine(params); + } + + virtual std::vector GetCommands() override + { + if (selectedCommand != nullptr) + { + return selectedCommand->GetCommands(); + } + + if (Matched()) + { + return Group::GetCommands(); + } + + return { this }; + } + + virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned int indent) const override + { + std::vector> descriptions; + unsigned addindent = 0; + + UpdateSubparserHelp(params); + + if (!Matched()) + { + if (params.showCommandFullHelp) + { + std::ostringstream s; + bool empty = true; + for (const auto &progline: GetCommandProgramLine(params)) + { + if (!empty) + { + s << ' '; + } + else + { + empty = false; + } + + s << progline; + } + + descriptions.emplace_back(s.str(), "", indent); + } + else + { + descriptions.emplace_back(Name(), help, indent); + } + + if (!params.showCommandChildren && !params.showCommandFullHelp) + { + return descriptions; + } + + addindent = 1; + } + + if (params.showCommandFullHelp && !Matched()) + { + descriptions.emplace_back("", "", indent + addindent); + descriptions.emplace_back(Description().empty() ? Help() : Description(), "", indent + addindent); + descriptions.emplace_back("", "", indent + addindent); + } + + for (Base *child: Children()) + { + if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None) + { + continue; + } + + auto groupDescriptions = child->GetDescription(params, indent + addindent); + descriptions.insert( + std::end(descriptions), + std::make_move_iterator(std::begin(groupDescriptions)), + std::make_move_iterator(std::end(groupDescriptions))); + } + + for (auto childDescription: subparserDescription) + { + std::get<2>(childDescription) += indent + addindent; + descriptions.push_back(std::move(childDescription)); + } + + if (params.showCommandFullHelp && !Matched()) + { + descriptions.emplace_back("", "", indent + addindent); + if (!Epilog().empty()) + { + descriptions.emplace_back(Epilog(), "", indent + addindent); + descriptions.emplace_back("", "", indent + addindent); + } + } + + return descriptions; + } + + virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override + { + if (!Matched()) + { + return; + } + + auto onValidationError = [&] + { + std::ostringstream problem; + problem << "Group validation failed somewhere!"; +#ifdef ARGS_NOEXCEPT + error = Error::Validation; + errorMsg = problem.str(); +#else + throw ValidationError(problem.str()); +#endif + }; + + for (Base *child: Children()) + { + if (child->IsGroup() && !child->Matched()) + { + onValidationError(); + } + + child->Validate(shortprefix, longprefix); + } + + if (subparser != nullptr) + { + subparser->Validate(shortprefix, longprefix); + if (!subparser->Matched()) + { + onValidationError(); + } + } + + if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand)) + { + std::ostringstream problem; + problem << "Command is required"; +#ifdef ARGS_NOEXCEPT + error = Error::Validation; + errorMsg = problem.str(); +#else + throw ValidationError(problem.str()); +#endif + } + } + + virtual void Reset() noexcept override + { + Group::Reset(); + selectedCommand = nullptr; + subparserProgramLine.clear(); + subparserDescription.clear(); + subparserHasFlag = false; + subparserHasPositional = false; + subparserHasCommand = false; +#ifdef ARGS_NOEXCEPT + subparserError = Error::None; +#endif + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const override + { + if (!Matched()) + { + return Error::None; + } + + if (error != Error::None) + { + return error; + } + + if (subparserError != Error::None) + { + return subparserError; + } + + return Group::GetError(); + } +#endif + }; + + /** The main user facing command line argument parser class + */ + class ArgumentParser : public Command + { + friend class Subparser; + + private: + std::string longprefix; + std::string shortprefix; + + std::string longseparator; + + std::string terminator; + + bool allowJoinedShortValue = true; + bool allowJoinedLongValue = true; + bool allowSeparateShortValue = true; + bool allowSeparateLongValue = true; + + CompletionFlag *completion = nullptr; + bool readCompletion = false; + + protected: + enum class OptionType + { + LongFlag, + ShortFlag, + Positional + }; + + OptionType ParseOption(const std::string &s, bool allowEmpty = false) + { + if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length())) + { + return OptionType::LongFlag; + } + + if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length())) + { + return OptionType::ShortFlag; + } + + return OptionType::Positional; + } + + template + bool Complete(FlagBase &flag, It it, It end) + { + auto nextIt = it; + if (!readCompletion || (++nextIt != end)) + { + return false; + } + + const auto &chunk = *it; + for (auto &choice : flag.HelpChoices(helpParams)) + { + AddCompletionReply(chunk, choice); + } + +#ifndef ARGS_NOEXCEPT + throw Completion(completion->Get()); +#else + return true; +#endif + } + + /** (INTERNAL) Parse flag's values + * + * \param arg The string to display in error message as a flag name + * \param[in, out] it The iterator to first value. It will point to the last value + * \param end The end iterator + * \param joinedArg Joined value (e.g. bar in --foo=bar) + * \param canDiscardJoined If true joined value can be parsed as flag not as a value (as in -abcd) + * \param[out] values The vector to store parsed arg's values + */ + template + std::string ParseArgsValues(FlagBase &flag, const std::string &arg, It &it, It end, + const bool allowSeparate, const bool allowJoined, + const bool hasJoined, const std::string &joinedArg, + const bool canDiscardJoined, std::vector &values) + { + values.clear(); + + Nargs nargs = flag.NumberOfArguments(); + + if (hasJoined && !allowJoined && nargs.min != 0) + { + return "Flag '" + arg + "' was passed a joined argument, but these are disallowed"; + } + + if (hasJoined) + { + if (!canDiscardJoined || nargs.max != 0) + { + values.push_back(joinedArg); + } + } else if (!allowSeparate) + { + if (nargs.min != 0) + { + return "Flag '" + arg + "' was passed a separate argument, but these are disallowed"; + } + } else + { + auto valueIt = it; + ++valueIt; + + while (valueIt != end && + values.size() < nargs.max && + (nargs.min == nargs.max || ParseOption(*valueIt) == OptionType::Positional)) + { + if (Complete(flag, valueIt, end)) + { + it = end; + return ""; + } + + values.push_back(*valueIt); + ++it; + ++valueIt; + } + } + + if (values.size() > nargs.max) + { + return "Passed an argument into a non-argument flag: " + arg; + } else if (values.size() < nargs.min) + { + if (nargs.min == 1 && nargs.max == 1) + { + return "Flag '" + arg + "' requires an argument but received none"; + } else if (nargs.min == 1) + { + return "Flag '" + arg + "' requires at least one argument but received none"; + } else if (nargs.min != nargs.max) + { + return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) + + " arguments but received " + std::to_string(values.size()); + } else + { + return "Flag '" + arg + "' requires " + std::to_string(nargs.min) + + " arguments but received " + std::to_string(values.size()); + } + } + + return {}; + } + + template + bool ParseLong(It &it, It end) + { + const auto &chunk = *it; + const auto argchunk = chunk.substr(longprefix.size()); + // Try to separate it, in case of a separator: + const auto separator = longseparator.empty() ? argchunk.npos : argchunk.find(longseparator); + // If the separator is in the argument, separate it. + const auto arg = (separator != argchunk.npos ? + std::string(argchunk, 0, separator) + : argchunk); + const auto joined = (separator != argchunk.npos ? + argchunk.substr(separator + longseparator.size()) + : std::string()); + + if (auto flag = Match(arg)) + { + std::vector values; + const std::string errorMessage = ParseArgsValues(*flag, arg, it, end, allowSeparateLongValue, allowJoinedLongValue, + separator != argchunk.npos, joined, false, values); + if (!errorMessage.empty()) + { +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + + if (!readCompletion) + { + flag->ParseValue(values); + } + + if (flag->KickOut()) + { + ++it; + return false; + } + } else + { + const std::string errorMessage("Flag could not be matched: " + arg); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + + return true; + } + + template + bool ParseShort(It &it, It end) + { + const auto &chunk = *it; + const auto argchunk = chunk.substr(shortprefix.size()); + for (auto argit = std::begin(argchunk); argit != std::end(argchunk); ++argit) + { + const auto arg = *argit; + + if (auto flag = Match(arg)) + { + const std::string value(argit + 1, std::end(argchunk)); + std::vector values; + const std::string errorMessage = ParseArgsValues(*flag, std::string(1, arg), it, end, + allowSeparateShortValue, allowJoinedShortValue, + !value.empty(), value, !value.empty(), values); + + if (!errorMessage.empty()) + { +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + + if (!readCompletion) + { + flag->ParseValue(values); + } + + if (flag->KickOut()) + { + ++it; + return false; + } + + if (!values.empty()) + { + break; + } + } else + { + const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'"); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + } + + return true; + } + + bool AddCompletionReply(const std::string &cur, const std::string &choice) + { + if (cur.empty() || choice.find(cur) == 0) + { + if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos) + { + completion->reply.push_back(choice.substr(choice.find(longseparator) + 1)); + } else + { + completion->reply.push_back(choice); + } + return true; + } + + return false; + } + + template + bool Complete(It it, It end) + { + auto nextIt = it; + if (!readCompletion || (++nextIt != end)) + { + return false; + } + + const auto &chunk = *it; + auto pos = GetNextPositional(); + std::vector commands = GetCommands(); + const auto optionType = ParseOption(chunk, true); + + if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional)) + { + for (auto &cmd : commands) + { + if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None) + { + AddCompletionReply(chunk, cmd->Name()); + } + } + } else + { + bool hasPositionalCompletion = true; + + if (!commands.empty()) + { + for (auto &cmd : commands) + { + if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None) + { + AddCompletionReply(chunk, cmd->Name()); + } + } + } else if (pos) + { + if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None) + { + auto choices = pos->HelpChoices(helpParams); + hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional; + for (auto &choice : choices) + { + AddCompletionReply(chunk, choice); + } + } + } + + if (hasPositionalCompletion) + { + auto flags = GetAllFlags(); + for (auto flag : flags) + { + if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None) + { + continue; + } + + auto &matcher = flag->GetMatcher(); + if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix))) + { + for (auto &flagName : matcher.GetFlagStrings()) + { + if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix))) + { + break; + } + } + } + } + + if (optionType == OptionType::LongFlag && allowJoinedLongValue) + { + const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator); + if (separator != chunk.npos) + { + std::string arg(chunk, 0, separator); + if (auto flag = this->Match(arg.substr(longprefix.size()))) + { + for (auto &choice : flag->HelpChoices(helpParams)) + { + AddCompletionReply(chunk, arg + longseparator + choice); + } + } + } + } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue) + { + if (chunk.size() > shortprefix.size() + 1) + { + auto arg = chunk.at(shortprefix.size()); + //TODO: support -abcVALUE where a and b take no value + if (auto flag = this->Match(arg)) + { + for (auto &choice : flag->HelpChoices(helpParams)) + { + AddCompletionReply(chunk, shortprefix + arg + choice); + } + } + } + } + } + } + +#ifndef ARGS_NOEXCEPT + throw Completion(completion->Get()); +#else + return true; +#endif + } + + template + It Parse(It begin, It end) + { + bool terminated = false; + std::vector commands = GetCommands(); + + // Check all arg chunks + for (auto it = begin; it != end; ++it) + { + if (Complete(it, end)) + { + return end; + } + + const auto &chunk = *it; + + if (!terminated && chunk == terminator) + { + terminated = true; + } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag) + { + if (!ParseLong(it, end)) + { + return it; + } + } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag) + { + if (!ParseShort(it, end)) + { + return it; + } + } else if (!terminated && !commands.empty()) + { + auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; }); + if (itCommand == commands.end()) + { + const std::string errorMessage("Unknown command: " + chunk); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return it; +#endif + } + + SelectCommand(*itCommand); + + if (const auto &coroutine = GetCoroutine()) + { + ++it; + RaiiSubparser coro(*this, std::vector(it, end)); + coroutine(coro.Parser()); +#ifdef ARGS_NOEXCEPT + error = GetError(); + if (error != Error::None) + { + return end; + } + + if (!coro.Parser().IsParsed()) + { + error = Error::Usage; + return end; + } +#else + if (!coro.Parser().IsParsed()) + { + throw UsageError("Subparser::Parse was not called"); + } +#endif + + break; + } + + commands = GetCommands(); + } else + { + auto pos = GetNextPositional(); + if (pos) + { + pos->ParseValue(chunk); + + if (pos->KickOut()) + { + return ++it; + } + } else + { + const std::string errorMessage("Passed in argument, but no positional arguments were ready to receive it: " + chunk); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return it; +#endif + } + } + + if (!readCompletion && completion != nullptr && completion->Matched()) + { +#ifdef ARGS_NOEXCEPT + error = Error::Completion; +#endif + readCompletion = true; + ++it; + const auto argsLeft = static_cast(std::distance(it, end)); + if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft) + { +#ifndef ARGS_NOEXCEPT + throw Completion(""); +#endif + } + + std::vector curArgs(++it, end); + curArgs.resize(completion->cword); + + if (completion->syntax == "bash") + { + // bash tokenizes --flag=value as --flag=value + for (size_t idx = 0; idx < curArgs.size(); ) + { + if (idx > 0 && curArgs[idx] == "=") + { + curArgs[idx - 1] += "="; + // Avoid warnings from -Wsign-conversion + const auto signedIdx = static_cast(idx); + if (idx + 1 < curArgs.size()) + { + curArgs[idx - 1] += curArgs[idx + 1]; + curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2); + } else + { + curArgs.erase(curArgs.begin() + signedIdx); + } + } else + { + ++idx; + } + } + + } +#ifndef ARGS_NOEXCEPT + try + { + Parse(curArgs.begin(), curArgs.end()); + throw Completion(""); + } + catch (Completion &) + { + throw; + } + catch (args::Error&) + { + throw Completion(""); + } +#else + return Parse(curArgs.begin(), curArgs.end()); +#endif + } + } + + Validate(shortprefix, longprefix); + return end; + } + + public: + HelpParams helpParams; + + ArgumentParser(const std::string &description_, const std::string &epilog_ = std::string()) + { + Description(description_); + Epilog(epilog_); + LongPrefix("--"); + ShortPrefix("-"); + LongSeparator("="); + Terminator("--"); + SetArgumentSeparations(true, true, true, true); + matched = true; + } + + void AddCompletion(CompletionFlag &completionFlag) + { + completion = &completionFlag; + Add(completionFlag); + } + + /** The program name for help generation + */ + const std::string &Prog() const + { return helpParams.programName; } + /** The program name for help generation + */ + void Prog(const std::string &prog_) + { this->helpParams.programName = prog_; } + + /** The prefix for long flags + */ + const std::string &LongPrefix() const + { return longprefix; } + /** The prefix for long flags + */ + void LongPrefix(const std::string &longprefix_) + { + this->longprefix = longprefix_; + this->helpParams.longPrefix = longprefix_; + } + + /** The prefix for short flags + */ + const std::string &ShortPrefix() const + { return shortprefix; } + /** The prefix for short flags + */ + void ShortPrefix(const std::string &shortprefix_) + { + this->shortprefix = shortprefix_; + this->helpParams.shortPrefix = shortprefix_; + } + + /** The separator for long flags + */ + const std::string &LongSeparator() const + { return longseparator; } + /** The separator for long flags + */ + void LongSeparator(const std::string &longseparator_) + { + if (longseparator_.empty()) + { + const std::string errorMessage("longseparator can not be set to empty"); +#ifdef ARGS_NOEXCEPT + error = Error::Usage; + errorMsg = errorMessage; +#else + throw UsageError(errorMessage); +#endif + } else + { + this->longseparator = longseparator_; + this->helpParams.longSeparator = allowJoinedLongValue ? longseparator_ : " "; + } + } + + /** The terminator that forcibly separates flags from positionals + */ + const std::string &Terminator() const + { return terminator; } + /** The terminator that forcibly separates flags from positionals + */ + void Terminator(const std::string &terminator_) + { this->terminator = terminator_; } + + /** Get the current argument separation parameters. + * + * See SetArgumentSeparations for details on what each one means. + */ + void GetArgumentSeparations( + bool &allowJoinedShortValue_, + bool &allowJoinedLongValue_, + bool &allowSeparateShortValue_, + bool &allowSeparateLongValue_) const + { + allowJoinedShortValue_ = this->allowJoinedShortValue; + allowJoinedLongValue_ = this->allowJoinedLongValue; + allowSeparateShortValue_ = this->allowSeparateShortValue; + allowSeparateLongValue_ = this->allowSeparateLongValue; + } + + /** Change allowed option separation. + * + * \param allowJoinedShortValue_ Allow a short flag that accepts an argument to be passed its argument immediately next to it (ie. in the same argv field) + * \param allowJoinedLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by the longseparator (ie. in the same argv field) + * \param allowSeparateShortValue_ Allow a short flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field) + * \param allowSeparateLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field) + */ + void SetArgumentSeparations( + const bool allowJoinedShortValue_, + const bool allowJoinedLongValue_, + const bool allowSeparateShortValue_, + const bool allowSeparateLongValue_) + { + this->allowJoinedShortValue = allowJoinedShortValue_; + this->allowJoinedLongValue = allowJoinedLongValue_; + this->allowSeparateShortValue = allowSeparateShortValue_; + this->allowSeparateLongValue = allowSeparateLongValue_; + + this->helpParams.longSeparator = allowJoinedLongValue ? longseparator : " "; + this->helpParams.shortSeparator = allowJoinedShortValue ? "" : " "; + } + + /** Pass the help menu into an ostream + */ + void Help(std::ostream &help_) const + { + auto &command = SelectedCommand(); + const auto &commandDescription = command.Description().empty() ? command.Help() : command.Description(); + const auto description_text = Wrap(commandDescription, helpParams.width - helpParams.descriptionindent); + const auto epilog_text = Wrap(command.Epilog(), helpParams.width - helpParams.descriptionindent); + + const bool hasoptions = command.HasFlag(); + const bool hasarguments = command.HasPositional(); + + std::vector prognameline; + prognameline.push_back(helpParams.usageString); + prognameline.push_back(Prog()); + auto commandProgLine = command.GetProgramLine(helpParams); + prognameline.insert(prognameline.end(), commandProgLine.begin(), commandProgLine.end()); + + const auto proglines = Wrap(prognameline.begin(), prognameline.end(), + helpParams.width - (helpParams.progindent + helpParams.progtailindent), + helpParams.width - helpParams.progindent); + auto progit = std::begin(proglines); + if (progit != std::end(proglines)) + { + help_ << std::string(helpParams.progindent, ' ') << *progit << '\n'; + ++progit; + } + for (; progit != std::end(proglines); ++progit) + { + help_ << std::string(helpParams.progtailindent, ' ') << *progit << '\n'; + } + + help_ << '\n'; + + if (!description_text.empty()) + { + for (const auto &line: description_text) + { + help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n"; + } + help_ << "\n"; + } + + bool lastDescriptionIsNewline = false; + + if (!helpParams.optionsString.empty()) + { + help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n"; + } + + for (const auto &desc: command.GetDescription(helpParams, 0)) + { + lastDescriptionIsNewline = std::get<0>(desc).empty() && std::get<1>(desc).empty(); + const auto groupindent = std::get<2>(desc) * helpParams.eachgroupindent; + const auto flags = Wrap(std::get<0>(desc), helpParams.width - (helpParams.flagindent + helpParams.helpindent + helpParams.gutter)); + const auto info = Wrap(std::get<1>(desc), helpParams.width - (helpParams.helpindent + groupindent)); + + std::string::size_type flagssize = 0; + for (auto flagsit = std::begin(flags); flagsit != std::end(flags); ++flagsit) + { + if (flagsit != std::begin(flags)) + { + help_ << '\n'; + } + help_ << std::string(groupindent + helpParams.flagindent, ' ') << *flagsit; + flagssize = Glyphs(*flagsit); + } + + auto infoit = std::begin(info); + // groupindent is on both sides of this inequality, and therefore can be removed + if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info) || helpParams.addNewlineBeforeDescription) + { + help_ << '\n'; + } else + { + // groupindent is on both sides of the minus sign, and therefore doesn't actually need to be in here + help_ << std::string(helpParams.helpindent - (helpParams.flagindent + flagssize), ' ') << *infoit << '\n'; + ++infoit; + } + for (; infoit != std::end(info); ++infoit) + { + help_ << std::string(groupindent + helpParams.helpindent, ' ') << *infoit << '\n'; + } + } + if (hasoptions && hasarguments && helpParams.showTerminator) + { + lastDescriptionIsNewline = false; + for (const auto &item: Wrap(std::string("\"") + terminator + "\" can be used to terminate flag options and force all following arguments to be treated as positional options", helpParams.width - helpParams.flagindent)) + { + help_ << std::string(helpParams.flagindent, ' ') << item << '\n'; + } + } + + if (!lastDescriptionIsNewline) + { + help_ << "\n"; + } + + for (const auto &line: epilog_text) + { + help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n"; + } + } + + /** Generate a help menu as a string. + * + * \return the help text as a single string + */ + std::string Help() const + { + std::ostringstream help_; + Help(help_); + return help_.str(); + } + + virtual void Reset() noexcept override + { + Command::Reset(); + matched = true; + readCompletion = false; + } + + /** Parse all arguments. + * + * \param begin an iterator to the beginning of the argument list + * \param end an iterator to the past-the-end element of the argument list + * \return the iterator after the last parsed value. Only useful for kick-out + */ + template + It ParseArgs(It begin, It end) + { + // Reset all Matched statuses and errors + Reset(); +#ifdef ARGS_NOEXCEPT + error = GetError(); + if (error != Error::None) + { + return end; + } +#endif + return Parse(begin, end); + } + + /** Parse all arguments. + * + * \param args an iterable of the arguments + * \return the iterator after the last parsed value. Only useful for kick-out + */ + template + auto ParseArgs(const T &args) -> decltype(std::begin(args)) + { + return ParseArgs(std::begin(args), std::end(args)); + } + + /** Convenience function to parse the CLI from argc and argv + * + * Just assigns the program name and vectorizes arguments for passing into ParseArgs() + * + * \return whether or not all arguments were parsed. This works for detecting kick-out, but is generally useless as it can't do anything with it. + */ + bool ParseCLI(const int argc, const char * const * argv) + { + if (Prog().empty()) + { + Prog(argv[0]); + } + const std::vector args(argv + 1, argv + argc); + return ParseArgs(args) == std::end(args); + } + + template + bool ParseCLI(const T &args) + { + return ParseArgs(args) == std::end(args); + } + }; + + inline Command::RaiiSubparser::RaiiSubparser(ArgumentParser &parser_, std::vector args_) + : command(parser_.SelectedCommand()), parser(std::move(args_), parser_, command, parser_.helpParams), oldSubparser(command.subparser) + { + command.subparser = &parser; + } + + inline Command::RaiiSubparser::RaiiSubparser(const Command &command_, const HelpParams ¶ms_): command(command_), parser(command, params_), oldSubparser(command.subparser) + { + command.subparser = &parser; + } + + inline void Subparser::Parse() + { + isParsed = true; + Reset(); + command.subparserDescription = GetDescription(helpParams, 0); + command.subparserHasFlag = HasFlag(); + command.subparserHasPositional = HasPositional(); + command.subparserHasCommand = HasCommand(); + command.subparserProgramLine = GetProgramLine(helpParams); + if (parser == nullptr) + { +#ifndef ARGS_NOEXCEPT + throw args::SubparserError(); +#else + error = Error::Subparser; + return; +#endif + } + + auto it = parser->Parse(args.begin(), args.end()); + command.Validate(parser->ShortPrefix(), parser->LongPrefix()); + kicked.assign(it, args.end()); + +#ifdef ARGS_NOEXCEPT + command.subparserError = GetError(); +#endif + } + + inline std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser) + { + parser.Help(os); + return os; + } + + /** Boolean argument matcher + */ + class Flag : public FlagBase + { + public: + Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): FlagBase(name_, help_, std::move(matcher_), options_) + { + group_.Add(*this); + } + + Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false): Flag(group_, name_, help_, std::move(matcher_), extraError_ ? Options::Single : Options::None) + { + } + + virtual ~Flag() {} + + /** Get whether this was matched + */ + bool Get() const + { + return Matched(); + } + + virtual Nargs NumberOfArguments() const noexcept override + { + return 0; + } + + virtual void ParseValue(const std::vector&) override + { + } + }; + + /** Help flag class + * + * Works like a regular flag, but throws an instance of Help when it is matched + */ + class HelpFlag : public Flag + { + public: + HelpFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_ = {}): Flag(group_, name_, help_, std::move(matcher_), options_) {} + + virtual ~HelpFlag() {} + + virtual void ParseValue(const std::vector &) + { +#ifdef ARGS_NOEXCEPT + error = Error::Help; + errorMsg = Name(); +#else + throw Help(Name()); +#endif + } + + /** Get whether this was matched + */ + bool Get() const noexcept + { + return Matched(); + } + }; + + /** A flag class that simply counts the number of times it's matched + */ + class CounterFlag : public Flag + { + private: + const int startcount; + int count; + + public: + CounterFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const int startcount_ = 0, Options options_ = {}): + Flag(group_, name_, help_, std::move(matcher_), options_), startcount(startcount_), count(startcount_) {} + + virtual ~CounterFlag() {} + + virtual FlagBase *Match(const EitherFlag &arg) override + { + auto me = FlagBase::Match(arg); + if (me) + { + ++count; + } + return me; + } + + /** Get the count + */ + int &Get() noexcept + { + return count; + } + + virtual void Reset() noexcept override + { + FlagBase::Reset(); + count = startcount; + } + }; + + /** A flag class that calls a function when it's matched + */ + class ActionFlag : public FlagBase + { + private: + std::function &)> action; + Nargs nargs; + + public: + ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, std::function &)> action_, Options options_ = {}): + FlagBase(name_, help_, std::move(matcher_), options_), action(std::move(action_)), nargs(nargs_) + { + group_.Add(*this); + } + + ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function action_, Options options_ = {}): + FlagBase(name_, help_, std::move(matcher_), options_), nargs(1) + { + group_.Add(*this); + action = [action_](const std::vector &a) { return action_(a.at(0)); }; + } + + ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function action_, Options options_ = {}): + FlagBase(name_, help_, std::move(matcher_), options_), nargs(0) + { + group_.Add(*this); + action = [action_](const std::vector &) { return action_(); }; + } + + virtual Nargs NumberOfArguments() const noexcept override + { return nargs; } + + virtual void ParseValue(const std::vector &value) override + { action(value); } + }; + + /** A default Reader class for argument classes + * + * If destination type is assignable to std::string it uses an assignment to std::string. + * Otherwise ValueReader simply uses a std::istringstream to read into the destination type, and + * raises a ParseError if there are any characters left. + */ + struct ValueReader + { + template + typename std::enable_if::value, bool>::type + operator ()(const std::string &name, const std::string &value, T &destination) + { + std::istringstream ss(value); + bool failed = !(ss >> destination); + + if (!failed) + { + ss >> std::ws; + } + + if (ss.rdbuf()->in_avail() > 0 || failed) + { +#ifdef ARGS_NOEXCEPT + (void)name; + return false; +#else + std::ostringstream problem; + problem << "Argument '" << name << "' received invalid value type '" << value << "'"; + throw ParseError(problem.str()); +#endif + } + return true; + } + + template + typename std::enable_if::value, bool>::type + operator()(const std::string &, const std::string &value, T &destination) + { + destination = value; + return true; + } + }; + + /** An argument-accepting flag class + * + * \tparam T the type to extract the argument as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + typename Reader = ValueReader> + class ValueFlag : public ValueFlagBase + { + protected: + T value; + T defaultValue; + + virtual std::string GetDefaultString(const HelpParams&) const override + { + return detail::ToString(defaultValue); + } + + private: + Reader reader; + + public: + + ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), const bool extraError_ = false): ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, extraError_ ? Options::Single : Options::None) + { + } + + ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): ValueFlag(group_, name_, help_, std::move(matcher_), T(), options_) + { + } + + virtual ~ValueFlag() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value_ = values_.at(0); + +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, this->value)) + { + error = Error::Parse; + } +#else + reader(name, value_, this->value); +#endif + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + value = defaultValue; + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + /** Get the default value + */ + const T &GetDefault() noexcept + { + return defaultValue; + } + }; + + /** An optional argument-accepting flag class + * + * \tparam T the type to extract the argument as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + typename Reader = ValueReader> + class ImplicitValueFlag : public ValueFlag + { + protected: + T implicitValue; + + public: + + ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &implicitValue_, const T &defaultValue_ = T(), Options options_ = {}) + : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_) + { + } + + ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), Options options_ = {}) + : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_) + { + } + + ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) + : ValueFlag(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue() + { + } + + virtual ~ImplicitValueFlag() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return {0, 1}; + } + + virtual void ParseValue(const std::vector &value_) override + { + if (value_.empty()) + { + this->value = implicitValue; + } else + { + ValueFlag::ParseValue(value_); + } + } + }; + + /** A variadic arguments accepting flag class + * + * \tparam T the type to extract the argument as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + template class List = detail::vector, + typename Reader = ValueReader> + class NargsValueFlag : public FlagBase + { + protected: + + List values; + const List defaultValues; + Nargs nargs; + Reader reader; + + public: + + typedef List Container; + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + NargsValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, const List &defaultValues_ = {}, Options options_ = {}) + : FlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_),nargs(nargs_) + { + group_.Add(*this); + } + + virtual ~NargsValueFlag() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return nargs; + } + + virtual void ParseValue(const std::vector &values_) override + { + values.clear(); + + for (const std::string &value : values_) + { + T v; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value, v)) + { + error = Error::Parse; + } +#else + reader(name, value, v); +#endif + values.insert(std::end(values), v); + } + } + + List &Get() noexcept + { + return values; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + + virtual void Reset() noexcept override + { + FlagBase::Reset(); + values = defaultValues; + } + + virtual FlagBase *Match(const EitherFlag &arg) override + { + const bool wasMatched = Matched(); + auto me = FlagBase::Match(arg); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + }; + + /** An argument-accepting flag class that pushes the found values into a list + * + * \tparam T the type to extract the argument as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + template class List = detail::vector, + typename Reader = ValueReader> + class ValueFlagList : public ValueFlagBase + { + private: + using Container = List; + Container values; + const Container defaultValues; + Reader reader; + + public: + + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + ValueFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Container &defaultValues_ = Container(), Options options_ = {}): + ValueFlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + virtual ~ValueFlagList() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value_ = values_.at(0); + + T v; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, v)) + { + error = Error::Parse; + } +#else + reader(name, value_, v); +#endif + values.insert(std::end(values), v); + } + + /** Get the values + */ + Container &Get() noexcept + { + return values; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + values = defaultValues; + } + + virtual FlagBase *Match(const EitherFlag &arg) override + { + const bool wasMatched = Matched(); + auto me = FlagBase::Match(arg); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; + + /** A mapping value flag class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapFlag : public ValueFlagBase + { + private: + const Map map; + T value; + const T defaultValue; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + + MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), map(map_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, const T &defaultValue_ = T(), const bool extraError_ = false): MapFlag(group_, name_, help_, std::move(matcher_), map_, defaultValue_, extraError_ ? Options::Single : Options::None) + { + } + + MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, Options options_): MapFlag(group_, name_, help_, std::move(matcher_), map_, T(), options_) + { + } + + virtual ~MapFlag() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value_ = values_.at(0); + + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, key)) + { + error = Error::Parse; + } +#else + reader(name, value_, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->value = it->second; + } + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + value = defaultValue; + } + }; + + /** A mapping value flag list class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + template class List = detail::vector, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapFlagList : public ValueFlagBase + { + private: + using Container = List; + const Map map; + Container values; + const Container defaultValues; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + MapFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, const Container &defaultValues_ = Container()): ValueFlagBase(name_, help_, std::move(matcher_)), map(map_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + virtual ~MapFlagList() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value = values_.at(0); + + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value, key)) + { + error = Error::Parse; + } +#else + reader(name, value, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->values.emplace_back(it->second); + } + } + + /** Get the value + */ + Container &Get() noexcept + { + return values; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + values = defaultValues; + } + + virtual FlagBase *Match(const EitherFlag &arg) override + { + const bool wasMatched = Matched(); + auto me = FlagBase::Match(arg); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; + + /** A positional argument class + * + * \tparam T the type to extract the argument as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + typename Reader = ValueReader> + class Positional : public PositionalBase + { + private: + T value; + const T defaultValue; + Reader reader; + public: + Positional(Group &group_, const std::string &name_, const std::string &help_, const T &defaultValue_ = T(), Options options_ = {}): PositionalBase(name_, help_, options_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + Positional(Group &group_, const std::string &name_, const std::string &help_, Options options_): Positional(group_, name_, help_, T(), options_) + { + } + + virtual ~Positional() {} + + virtual void ParseValue(const std::string &value_) override + { +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, this->value)) + { + error = Error::Parse; + } +#else + reader(name, value_, this->value); +#endif + ready = false; + matched = true; + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + value = defaultValue; + } + }; + + /** A positional argument class that pushes the found values into a list + * + * \tparam T the type to extract the argument as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + template class List = detail::vector, + typename Reader = ValueReader> + class PositionalList : public PositionalBase + { + private: + using Container = List; + Container values; + const Container defaultValues; + Reader reader; + + public: + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + PositionalList(Group &group_, const std::string &name_, const std::string &help_, const Container &defaultValues_ = Container(), Options options_ = {}): PositionalBase(name_, help_, options_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + PositionalList(Group &group_, const std::string &name_, const std::string &help_, Options options_): PositionalList(group_, name_, help_, {}, options_) + { + } + + virtual ~PositionalList() {} + + virtual void ParseValue(const std::string &value_) override + { + T v; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, v)) + { + error = Error::Parse; + } +#else + reader(name, value_, v); +#endif + values.insert(std::end(values), v); + matched = true; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + /** Get the values + */ + Container &Get() noexcept + { + return values; + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + values = defaultValues; + } + + virtual PositionalBase *GetNextPositional() override + { + const bool wasMatched = Matched(); + auto me = PositionalBase::GetNextPositional(); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; + + /** A positional argument mapping class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapPositional : public PositionalBase + { + private: + const Map map; + T value; + const T defaultValue; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + + MapPositional(Group &group_, const std::string &name_, const std::string &help_, const Map &map_, const T &defaultValue_ = T(), Options options_ = {}): + PositionalBase(name_, help_, options_), map(map_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + virtual ~MapPositional() {} + + virtual void ParseValue(const std::string &value_) override + { + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, key)) + { + error = Error::Parse; + } +#else + reader(name, value_, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->value = it->second; + ready = false; + matched = true; + } + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + value = defaultValue; + } + }; + + /** A positional argument mapping list class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + template class List = detail::vector, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapPositionalList : public PositionalBase + { + private: + using Container = List; + + const Map map; + Container values; + const Container defaultValues; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + MapPositionalList(Group &group_, const std::string &name_, const std::string &help_, const Map &map_, const Container &defaultValues_ = Container(), Options options_ = {}): + PositionalBase(name_, help_, options_), map(map_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + virtual ~MapPositionalList() {} + + virtual void ParseValue(const std::string &value_) override + { + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, key)) + { + error = Error::Parse; + } +#else + reader(name, value_, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->values.emplace_back(it->second); + matched = true; + } + } + + /** Get the value + */ + Container &Get() noexcept + { + return values; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + values = defaultValues; + } + + virtual PositionalBase *GetNextPositional() override + { + const bool wasMatched = Matched(); + auto me = PositionalBase::GetNextPositional(); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; +} + +#endif diff --git a/extern/json.hpp b/extern/json.hpp new file mode 100644 index 0000000..50b3a4a --- /dev/null +++ b/extern/json.hpp @@ -0,0 +1,22875 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.7.3 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +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 INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 7 +#define NLOHMANN_JSON_VERSION_PATCH 3 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // and, not +#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 + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +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 +} // namespace nlohmann + +// #include + + +#include // pair +// #include +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) +#if defined(JSON_HEDLEY_VERSION) +#undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 11 + +#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_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) +#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) +#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) +#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(_MSC_VER) +#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) +#define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) +#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_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__) +#define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#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_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_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_TI_VERSION) && \ + !defined(__COMPCERT__) +#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) +#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) __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) __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_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 + +/* 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) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# 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 +#else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#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(6,0,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) +#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(8,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 + +#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_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_TI_VERSION_CHECK(8,0,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_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(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") +#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_MSVC_VERSION_CHECK(19,0,0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#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(8,0,0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#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_DEPRECATED) +#undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) +#undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if 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_EXTENSION(attribute_deprecated_with_message) || \ + 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(8,3,0) +#define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,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_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,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) +#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(__cplusplus) && (__cplusplus >= 201703L) +#define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ + 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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +#define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ +#define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#else +#define JSON_HEDLEY_WARN_UNUSED_RESULT +#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) +#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) +#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(18,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#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) +#define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_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 \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) +#define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) +#define JSON_HEDLEY_UNREACHABLE() __assume(0) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) +#if defined(__cplusplus) +#define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) +#else +#define JSON_HEDLEY_UNREACHABLE() _nassert(0) +#endif +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#elif defined(EXIT_FAILURE) +#define JSON_HEDLEY_UNREACHABLE() abort() +#else +#define JSON_HEDLEY_UNREACHABLE() +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() +#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) +#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_VERSION_CHECK(6,0,0) +#if defined(__cplusplus) +#define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) +#else +#define JSON_HEDLEY_ASSUME(expr) _nassert(expr) +#endif +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) +#define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) +#else +#define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) +#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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#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) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) +# 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) +#if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) +#define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) +#endif +#elif \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + 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(6,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + JSON_HEDLEY_CONSTEXPR 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__ ({ \ + JSON_HEDLEY_CONSTEXPR 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) (((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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#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) +#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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +#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 JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +#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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) +#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_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_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) +#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_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) +#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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) +#define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) +#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(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,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_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) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#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) +#define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,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_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) +#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) +#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_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) +#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)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + 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_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) || \ + 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) || \ + (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,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_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) +#define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) +#else +#define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#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) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,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) +#define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#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) +#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 +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// 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 (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 + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow to disable 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 + +/*! +@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> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ +public: +/// returns the explanatory string +JSON_HEDLEY_RETURNS_NON_NULL +const char* what() const noexcept override +{ +return m.what(); +} + +/// the id of the exception +const int id; + +protected: +JSON_HEDLEY_NON_NULL(3) +exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + +static std::string name(const std::string& ename, int id_) +{ +return "[json.exception." + ename + "." + std::to_string(id_) + "] "; +} + +private: +/// an exception object as storage for error messages +std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ +public: +/*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ +static parse_error create(int id_, const position_t& pos, const std::string& what_arg) +{ +std::string w = exception::name("parse_error", id_) + "parse error" + +position_string(pos) + ": " + what_arg; +return parse_error(id_, pos.chars_read_total, w.c_str()); +} + +static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) +{ +std::string w = exception::name("parse_error", id_) + "parse error" + +(byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + +": " + what_arg; +return parse_error(id_, byte_, w.c_str()); +} + +/*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ +const std::size_t byte; + +private: +parse_error(int id_, std::size_t byte_, const char* what_arg) +: exception(id_, what_arg), byte(byte_) {} + +static std::string position_string(const position_t& pos) +{ +return " at line " + std::to_string(pos.lines_read + 1) + +", column " + std::to_string(pos.chars_read_current_line); +} +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ +public: +static invalid_iterator create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("invalid_iterator", id_) + what_arg; +return invalid_iterator(id_, w.c_str()); +} + +private: +JSON_HEDLEY_NON_NULL(3) +invalid_iterator(int id_, const char* what_arg) +: exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ +public: +static type_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("type_error", id_) + what_arg; +return type_error(id_, w.c_str()); +} + +private: +JSON_HEDLEY_NON_NULL(3) +type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ +public: +static out_of_range create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("out_of_range", id_) + what_arg; +return out_of_range(id_, w.c_str()); +} + +private: +JSON_HEDLEY_NON_NULL(3) +out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ +public: +static other_error create(int id_, const std::string& what_arg) +{ +std::string w = exception::name("other_error", id_) + what_arg; +return other_error(id_, w.c_str()); +} + +private: +JSON_HEDLEY_NON_NULL(3) +other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ +using type = index_sequence; +using value_type = std::size_t; +static constexpr std::size_t size() noexcept +{ +return sizeof...(Ints); +} +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> +: index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence +: merge_and_renumber < typename make_index_sequence < N / 2 >::type, +typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// 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 constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ +using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +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 +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +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