From 17f0b0b3bc65ffba39bf6f22a12b2cc7fcb9bafd Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 6 Jul 2019 02:03:50 +0200 Subject: [PATCH 01/16] Proof-of-concept of JSON export limited to PrimeMeridian (refs #1545) --- include/proj/common.hpp | 5 + include/proj/datum.hpp | 6 +- include/proj/io.hpp | 72 ++++++ include/proj/metadata.hpp | 6 +- scripts/reference_exported_symbols.txt | 7 + src/Makefile.am | 6 +- src/iso19111/common.cpp | 65 ++++++ src/iso19111/datum.cpp | 35 +++ src/iso19111/io.cpp | 87 ++++++++ src/iso19111/metadata.cpp | 20 ++ src/lib_proj.cmake | 2 + src/proj_json_streaming_writer.cpp | 297 +++++++++++++++++++++++++ src/proj_json_streaming_writer.hpp | 145 ++++++++++++ test/unit/test_datum.cpp | 28 +++ 14 files changed, 777 insertions(+), 4 deletions(-) create mode 100644 src/proj_json_streaming_writer.cpp create mode 100644 src/proj_json_streaming_writer.hpp diff --git a/include/proj/common.hpp b/include/proj/common.hpp index 7940f4fcc7..d857dafdd9 100644 --- a/include/proj/common.hpp +++ b/include/proj/common.hpp @@ -104,6 +104,9 @@ class PROJ_GCC_DLL UnitOfMeasure : public util::BaseObject { const std::string &unitType = std::string()) const; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON( + io::JSONFormatter *formatter) const; // throw(io::FormattingException) + PROJ_INTERNAL std::string exportToPROJString() const; PROJ_INTERNAL bool @@ -329,6 +332,8 @@ class PROJ_GCC_DLL IdentifiedObject : public util::BaseObject, formatID(io::WKTFormatter *formatter) const; PROJ_INTERNAL void formatRemarks(io::WKTFormatter *formatter) const; + PROJ_INTERNAL void formatID(io::JSONFormatter *formatter) const; + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = diff --git a/include/proj/datum.hpp b/include/proj/datum.hpp index b741649736..47bab4a07b 100644 --- a/include/proj/datum.hpp +++ b/include/proj/datum.hpp @@ -171,7 +171,8 @@ using PrimeMeridianNNPtr = util::nn; * \remark Implements PrimeMeridian from \ref ISO_19111_2019 */ class PROJ_GCC_DLL PrimeMeridian final : public common::IdentifiedObject, - public io::IPROJStringExportable { + public io::IPROJStringExportable, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~PrimeMeridian() override; @@ -198,6 +199,9 @@ class PROJ_GCC_DLL PrimeMeridian final : public common::IdentifiedObject, PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(io::FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = diff --git a/include/proj/io.hpp b/include/proj/io.hpp index c553598d12..71a6430d7b 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -38,6 +38,7 @@ #include "proj.h" +#include "proj_json_streaming_writer.hpp" #include "util.hpp" NS_PROJ_START @@ -455,6 +456,77 @@ class PROJ_GCC_DLL PROJStringFormatter { // --------------------------------------------------------------------------- +class JSONFormatter; +/** JSONFormatter unique pointer. */ +using JSONFormatterPtr = std::unique_ptr; +/** Non-null JSONFormatter unique pointer. */ +using JSONFormatterNNPtr = util::nn; + +/** \brief Formatter to JSON strings. + * + * An instance of this class can only be used by a single + * thread at a time. + */ +class PROJ_GCC_DLL JSONFormatter { + public: + PROJ_DLL static JSONFormatterNNPtr + create(DatabaseContextPtr dbContext = nullptr); + //! @cond Doxygen_Suppress + PROJ_DLL ~JSONFormatter(); + //! @endcond + + PROJ_DLL JSONFormatter &setMultiLine(bool multiLine) noexcept; + PROJ_DLL JSONFormatter &setIndentationWidth(int width) noexcept; + + PROJ_DLL const std::string &toString() const; + + PROJ_PRIVATE : + + //! @cond Doxygen_Suppress + PROJ_INTERNAL PROJ::CPLJSonStreamingWriter & + writer() const; + + // cppcheck-suppress functionStatic + PROJ_INTERNAL bool outputId() const; + + //! @endcond + + protected: + //! @cond Doxygen_Suppress + PROJ_INTERNAL explicit JSONFormatter(); + JSONFormatter(const JSONFormatter &other) = delete; + + INLINED_MAKE_UNIQUE + //! @endcond + + private: + PROJ_OPAQUE_PRIVATE_DATA +}; + +// --------------------------------------------------------------------------- + +/** \brief Interface for an object that can be exported to JSON. */ +class PROJ_GCC_DLL IJSONExportable { + public: + //! @cond Doxygen_Suppress + PROJ_DLL virtual ~IJSONExportable(); + //! @endcond + + /** Builds a JSON representation. May throw a FormattingException */ + PROJ_DLL std::string + exportToJSON(JSONFormatter *formatter) const; // throw(FormattingException) + + PROJ_PRIVATE : + + //! @cond Doxygen_Suppress + PROJ_INTERNAL virtual void + _exportToJSON( + JSONFormatter *formatter) const = 0; // throw(FormattingException) + //! @endcond +}; + +// --------------------------------------------------------------------------- + /** \brief Exception possibly thrown by IWKTExportable::exportToWKT() or * IPROJStringExportable::exportToPROJString(). */ class PROJ_GCC_DLL FormattingException : public util::Exception { diff --git a/include/proj/metadata.hpp b/include/proj/metadata.hpp index d32996fbd7..37241e6f5e 100644 --- a/include/proj/metadata.hpp +++ b/include/proj/metadata.hpp @@ -361,7 +361,8 @@ using IdentifierNNPtr = util::nn; * originates from \ref ISO_19115 */ class PROJ_GCC_DLL Identifier : public util::BaseObject, - public io::IWKTExportable { + public io::IWKTExportable, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL Identifier(const Identifier &other); @@ -401,6 +402,9 @@ class PROJ_GCC_DLL Identifier : public util::BaseObject, PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(io::FormattingException) + //! @endcond protected: diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index f3d13bd7c9..51ef425abb 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -331,10 +331,17 @@ osgeo::proj::io::FactoryException::FactoryException(osgeo::proj::io::FactoryExce osgeo::proj::io::FactoryException::FactoryException(std::string const&) osgeo::proj::io::FormattingException::~FormattingException() osgeo::proj::io::FormattingException::FormattingException(osgeo::proj::io::FormattingException const&) +osgeo::proj::io::IJSONExportable::exportToJSON(osgeo::proj::io::JSONFormatter*) const +osgeo::proj::io::IJSONExportable::~IJSONExportable() osgeo::proj::io::IPROJStringExportable::exportToPROJString(osgeo::proj::io::PROJStringFormatter*) const osgeo::proj::io::IPROJStringExportable::~IPROJStringExportable() osgeo::proj::io::IWKTExportable::exportToWKT(osgeo::proj::io::WKTFormatter*) const osgeo::proj::io::IWKTExportable::~IWKTExportable() +osgeo::proj::io::JSONFormatter::create(std::shared_ptr) +osgeo::proj::io::JSONFormatter::~JSONFormatter() +osgeo::proj::io::JSONFormatter::setIndentationWidth(int) +osgeo::proj::io::JSONFormatter::setMultiLine(bool) +osgeo::proj::io::JSONFormatter::toString() const osgeo::proj::io::NoSuchAuthorityCodeException::getAuthorityCode() const osgeo::proj::io::NoSuchAuthorityCodeException::getAuthority() const osgeo::proj::io::NoSuchAuthorityCodeException::~NoSuchAuthorityCodeException() diff --git a/src/Makefile.am b/src/Makefile.am index aed5a3936b..e50a56388d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,7 @@ AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ AM_CXXFLAGS = @CXX_WFLAGS@ @FLTO_FLAG@ include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesic.h \ - org_proj4_PJ.h proj_symbol_rename.h + org_proj4_PJ.h proj_symbol_rename.h proj_json_streaming_writer.hpp EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \ bin_geod.cmake bin_proj.cmake bin_projinfo.cmake \ @@ -208,7 +208,9 @@ libproj_la_SOURCES = \ wkt1_parser.h wkt1_parser.cpp \ wkt1_generated_parser.h wkt1_generated_parser.c \ wkt2_parser.h wkt2_parser.cpp \ - wkt2_generated_parser.h wkt2_generated_parser.c + wkt2_generated_parser.h wkt2_generated_parser.c \ + \ + proj_json_streaming_writer.cpp # The sed hack is to please MSVC diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp index d46da0da59..f2a510323b 100644 --- a/src/iso19111/common.cpp +++ b/src/iso19111/common.cpp @@ -236,6 +236,54 @@ void UnitOfMeasure::_exportToWKT( } formatter->endNode(); } + +// --------------------------------------------------------------------------- + +void UnitOfMeasure::_exportToJSON( + JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer); + writer.AddObjKey("type"); + const auto l_type = type(); + if (l_type == Type::LINEAR) { + writer.Add("LinearUnit"); + } else if (l_type == Type::ANGULAR) { + writer.Add("AngularUnit"); + } else if (l_type == Type::SCALE) { + writer.Add("ScaleUnit"); + } else if (l_type == Type::TIME) { + writer.Add("TimeUnit"); + } else if (l_type == Type::PARAMETRIC) { + writer.Add("ParametericUnit"); + } else { + writer.Add("Unit"); + } + + writer.AddObjKey("name"); + const auto &l_name = name(); + writer.Add(l_name); + + const auto &factor = conversionToSI(); + writer.AddObjKey("conversion_factor"); + writer.Add(factor, 15); + + const auto &l_codeSpace = codeSpace(); + if (!l_codeSpace.empty() && formatter->outputId()) { + writer.AddObjKey("id"); + PROJ::CPLJSonStreamingWriter::ObjectContext idContext(writer); + writer.AddObjKey("authority"); + writer.Add(l_codeSpace); + writer.AddObjKey("code"); + const auto &l_code = code(); + try { + writer.Add(std::stoi(l_code)); + } catch (const std::exception &) { + writer.Add(l_code); + } + } +} + //! @endcond // --------------------------------------------------------------------------- @@ -815,6 +863,23 @@ void IdentifiedObject::formatRemarks(WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +void IdentifiedObject::formatID(JSONFormatter *formatter) const { + const auto &ids(identifiers()); + auto &writer = formatter->writer(); + if (ids.size() == 1) { + writer.AddObjKey("id"); + ids.front()->_exportToJSON(formatter); + } else if (!ids.empty()) { + writer.AddObjKey("ids"); + PROJ::CPLJSonStreamingWriter::ArrayContext arrayContext(writer); + for (const auto &id : ids) { + id->_exportToJSON(formatter); + } + } +} + +// --------------------------------------------------------------------------- + bool IdentifiedObject::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion) const { diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index bf3092c189..6ba219d4ec 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -347,6 +347,41 @@ void PrimeMeridian::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void PrimeMeridian::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + PROJ::CPLJSonStreamingWriter::ObjectContext objectContext(writer); + + writer.AddObjKey("type"); + writer.Add("PrimeMeridian"); + + writer.AddObjKey("name"); + std::string l_name = + name()->description().has_value() ? nameStr() : "Greenwich"; + writer.Add(l_name); + + const auto &l_long = longitude(); + writer.AddObjKey("longitude"); + { + PROJ::CPLJSonStreamingWriter::ObjectContext longitudeContext(writer); + writer.AddObjKey("value"); + writer.Add(l_long.value(), 15); + + const auto &unit = l_long.unit(); + writer.AddObjKey("unit"); + unit._exportToJSON(formatter); + } + + if (formatter->outputId()) { + formatID(formatter); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress std::string PrimeMeridian::getPROJStringWellKnownName(const common::Angle &angle) { diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 0db97d0b41..0c9f8a0ca7 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -60,6 +60,7 @@ #include "proj_constants.h" +#include "proj_json_streaming_writer.hpp" #include "wkt1_parser.h" #include "wkt2_parser.h" @@ -8016,5 +8017,91 @@ PROJStringParser::createFromPROJString(const std::string &projString) { nullptr, nullptr, {}); } +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +struct JSONFormatter::Private { + PROJ::CPLJSonStreamingWriter writer_{nullptr, nullptr}; + DatabaseContextPtr dbContext_{}; + std::string result_{}; +}; +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Constructs a new formatter. + * + * A formatter can be used only once (its internal state is mutated) + * + * @return new formatter. + */ +JSONFormatterNNPtr JSONFormatter::create( // cppcheck-suppress passedByValue + DatabaseContextPtr dbContext) { + auto ret = NN_NO_CHECK(JSONFormatter::make_unique()); + ret->d->dbContext_ = dbContext; + return ret; +} + +// --------------------------------------------------------------------------- + +/** \brief Whether to use multi line output or not. */ +JSONFormatter &JSONFormatter::setMultiLine(bool multiLine) noexcept { + d->writer_.SetPrettyFormatting(multiLine); + return *this; +} + +// --------------------------------------------------------------------------- + +/** \brief Set number of spaces for each indentation level (defaults to 4). + */ +JSONFormatter &JSONFormatter::setIndentationWidth(int width) noexcept { + d->writer_.SetIndentationSize(width); + return *this; +} + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress + +JSONFormatter::JSONFormatter() : d(internal::make_unique()) {} + +// --------------------------------------------------------------------------- + +JSONFormatter::~JSONFormatter() = default; + +// --------------------------------------------------------------------------- + +PROJ::CPLJSonStreamingWriter &JSONFormatter::writer() const { + return d->writer_; +} + +// --------------------------------------------------------------------------- + +bool JSONFormatter::outputId() const { return true; } + +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Return the serialized JSON. + */ +const std::string &JSONFormatter::toString() const { + return d->writer_.GetString(); +} + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +IJSONExportable::~IJSONExportable() = default; + +// --------------------------------------------------------------------------- + +std::string IJSONExportable::exportToJSON(JSONFormatter *formatter) const { + _exportToJSON(formatter); + return formatter->toString(); +} + +//! @endcond + } // namespace io NS_PROJ_END diff --git a/src/iso19111/metadata.cpp b/src/iso19111/metadata.cpp index 3725b0726b..761b909b41 100644 --- a/src/iso19111/metadata.cpp +++ b/src/iso19111/metadata.cpp @@ -1088,6 +1088,26 @@ void Identifier::_exportToWKT(WKTFormatter *formatter) const { } } } + +// --------------------------------------------------------------------------- + +void Identifier::_exportToJSON(JSONFormatter *formatter) const { + const std::string &l_code = code(); + const std::string &l_codeSpace = *codeSpace(); + if (!l_codeSpace.empty() && !l_code.empty()) { + auto &writer = formatter->writer(); + PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer); + writer.AddObjKey("authority"); + writer.Add(l_codeSpace); + writer.AddObjKey("code"); + try { + writer.Add(std::stoi(l_code)); + } catch (const std::exception &) { + writer.Add(l_code); + } + } +} + //! @endcond // --------------------------------------------------------------------------- diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index 5a0a80707f..bad60324cb 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -285,6 +285,7 @@ set(SRC_LIBPROJ_CORE wkt_parser.cpp wkt_parser.hpp zpoly1.cpp + proj_json_streaming_writer.cpp ${CMAKE_CURRENT_BINARY_DIR}/proj_config.h ) @@ -293,6 +294,7 @@ set(HEADERS_LIBPROJ proj.h proj_experimental.h proj_constants.h + proj_json_streaming_writer.hpp geodesic.h ) diff --git a/src/proj_json_streaming_writer.cpp b/src/proj_json_streaming_writer.cpp new file mode 100644 index 0000000000..3198308bd2 --- /dev/null +++ b/src/proj_json_streaming_writer.cpp @@ -0,0 +1,297 @@ +/****************************************************************************** + * + * Project: CPL - Common Portability Library + * Purpose: JSon streaming writer + * Author: Even Rouault, even.rouault at spatialys.com + * + ****************************************************************************** + * Copyright (c) 2019, Even Rouault + * + * 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. + ****************************************************************************/ + +/*! @cond Doxygen_Suppress */ + +#include +#include + +#include "proj_json_streaming_writer.hpp" + +#include +#include +#include +#include +#define CPLAssert(x) do {} while(0) +#define CPLIsNan std::isnan +#define CPLIsInf std::isinf +#define CPL_FRMT_GIB "%lld" +#define CPL_FRMT_GUIB "%llu" +typedef std::uint64_t GUIntBig; + +static std::string CPLSPrintf(const char* fmt, ...) +{ + std::string res; + res.resize(256); + va_list list; + va_start(list, fmt); + sqlite3_vsnprintf(256, &res[0], fmt, list); + va_end(list); + res.resize(strlen(&res[0])); + return res; +} + +namespace PROJ +{ + +CPLJSonStreamingWriter::CPLJSonStreamingWriter( + SerializationFuncType pfnSerializationFunc, + void* pUserData): + m_pfnSerializationFunc(pfnSerializationFunc), + m_pUserData(pUserData) +{} + +CPLJSonStreamingWriter::~CPLJSonStreamingWriter() +{ + CPLAssert( m_nLevel == 0 ); + CPLAssert( m_states.empty() ); +} + +void CPLJSonStreamingWriter::Print(const std::string& text) +{ + if( m_pfnSerializationFunc ) + { + m_pfnSerializationFunc(text.c_str(), m_pUserData); + } + else + { + m_osStr += text; + } +} + +void CPLJSonStreamingWriter::SetIndentationSize(int nSpaces) +{ + CPLAssert( m_nLevel == 0 ); + m_osIndent.clear(); + m_osIndent.resize(nSpaces, ' '); +} + +void CPLJSonStreamingWriter::IncIndent() +{ + m_nLevel ++; + if( m_bPretty ) + m_osIndentAcc += m_osIndent; +} + +void CPLJSonStreamingWriter::DecIndent() +{ + CPLAssert(m_nLevel > 0); + m_nLevel --; + if( m_bPretty ) + m_osIndentAcc.resize(m_osIndentAcc.size() - m_osIndent.size()); +} + +std::string CPLJSonStreamingWriter::FormatString(const std::string& str) +{ + std::string ret; + ret += '"'; + for( char ch: str ) + { + switch(ch) + { + case '"' : ret += "\\\""; break; + case '\\': ret += "\\\\"; break; + case '\b': ret += "\\b"; break; + case '\f': ret += "\\f"; break; + case '\n': ret += "\\n"; break; + case '\r': ret += "\\r"; break; + case '\t': ret += "\\t"; break; + default: + if( static_cast(ch) < ' ' ) + ret += CPLSPrintf("\\u%04X", ch); + else + ret += ch; + break; + } + } + ret += '"'; + return ret; +} + +void CPLJSonStreamingWriter::EmitCommaIfNeeded() +{ + if( m_bWaitForValue ) + { + m_bWaitForValue = false; + } + else if( !m_states.empty() ) + { + if( !m_states.back().bFirstChild ) + { + Print(","); + if( m_bPretty && !m_bNewLineEnabled ) + Print(" "); + } + if( m_bPretty && m_bNewLineEnabled ) + { + Print("\n"); + Print(m_osIndentAcc); + } + m_states.back().bFirstChild = false; + } +} + +void CPLJSonStreamingWriter::StartObj() +{ + EmitCommaIfNeeded(); + Print("{"); + IncIndent(); + m_states.emplace_back(State(true)); +} + +void CPLJSonStreamingWriter::EndObj() +{ + CPLAssert(!m_bWaitForValue); + CPLAssert( !m_states.empty() ); + CPLAssert( m_states.back().bIsObj ); + DecIndent(); + if( !m_states.back().bFirstChild ) + { + if( m_bPretty && m_bNewLineEnabled ) + { + Print("\n"); + Print(m_osIndentAcc); + } + } + m_states.pop_back(); + Print("}"); +} + +void CPLJSonStreamingWriter::StartArray() +{ + EmitCommaIfNeeded(); + Print("["); + IncIndent(); + m_states.emplace_back(State(false)); +} + +void CPLJSonStreamingWriter::EndArray() +{ + CPLAssert( !m_states.empty() ); + CPLAssert( !m_states.back().bIsObj ); + DecIndent(); + if( !m_states.back().bFirstChild ) + { + if( m_bPretty && m_bNewLineEnabled ) + { + Print("\n"); + Print(m_osIndentAcc); + } + } + m_states.pop_back(); + Print("]"); +} + +void CPLJSonStreamingWriter::AddObjKey(const std::string& key) +{ + CPLAssert( !m_states.empty() ); + CPLAssert( m_states.back().bIsObj ); + CPLAssert(!m_bWaitForValue); + EmitCommaIfNeeded(); + Print(FormatString(key)); + Print(m_bPretty ? ": " : ":"); + m_bWaitForValue = true; +} + +void CPLJSonStreamingWriter::Add(bool bVal) +{ + EmitCommaIfNeeded(); + Print(bVal ? "true" : "false"); +} + +void CPLJSonStreamingWriter::Add(const std::string& str) +{ + EmitCommaIfNeeded(); + Print(FormatString(str)); +} + +void CPLJSonStreamingWriter::Add(const char* pszStr) +{ + EmitCommaIfNeeded(); + Print(FormatString(pszStr)); +} + +void CPLJSonStreamingWriter::Add(GIntBig nVal) +{ + EmitCommaIfNeeded(); + Print(CPLSPrintf(CPL_FRMT_GIB, nVal)); +} + +void CPLJSonStreamingWriter::Add(GUInt64 nVal) +{ + EmitCommaIfNeeded(); + Print(CPLSPrintf(CPL_FRMT_GUIB, static_cast(nVal))); +} + +void CPLJSonStreamingWriter::Add(float fVal, int nPrecision) +{ + EmitCommaIfNeeded(); + if( CPLIsNan(fVal) ) + { + Print("\"NaN\""); + } + else if( CPLIsInf(fVal) ) + { + Print( fVal > 0 ? "\"Infinity\"" : "\"-Infinity\"" ); + } + else + { + char szFormatting[10]; + snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision); + Print(CPLSPrintf(szFormatting, fVal)); + } +} + +void CPLJSonStreamingWriter::Add(double dfVal, int nPrecision) +{ + EmitCommaIfNeeded(); + if( CPLIsNan(dfVal) ) + { + Print("\"NaN\""); + } + else if( CPLIsInf(dfVal) ) + { + Print( dfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"" ); + } + else + { + char szFormatting[10]; + snprintf(szFormatting, sizeof(szFormatting), "%%.%dg", nPrecision); + Print(CPLSPrintf(szFormatting, dfVal)); + } +} + +void CPLJSonStreamingWriter::AddNull() +{ + EmitCommaIfNeeded(); + Print("null"); +} + +} // namespace PROJ + +/*! @endcond */ diff --git a/src/proj_json_streaming_writer.hpp b/src/proj_json_streaming_writer.hpp new file mode 100644 index 0000000000..d151044958 --- /dev/null +++ b/src/proj_json_streaming_writer.hpp @@ -0,0 +1,145 @@ +/****************************************************************************** + * + * Project: CPL - Common Portability Library + * Purpose: JSon streaming writer + * Author: Even Rouault, even.rouault at spatialys.com + * + ****************************************************************************** + * Copyright (c) 2019, Even Rouault + * + * 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 PROJ_JSON_STREAMING_WRITER_H +#define PROJ_JSON_STREAMING_WRITER_H + +/*! @cond Doxygen_Suppress */ + +#include +#include + +#define CPL_DLL + +namespace PROJ +{ + +typedef std::int64_t GIntBig; +typedef std::uint64_t GUInt64; + +class CPL_DLL CPLJSonStreamingWriter +{ +public: + typedef void (*SerializationFuncType)(const char* pszTxt, void* pUserData); + +private: + CPLJSonStreamingWriter(const CPLJSonStreamingWriter&) = delete; + CPLJSonStreamingWriter& operator=(const CPLJSonStreamingWriter&) = delete; + + std::string m_osStr{}; + SerializationFuncType m_pfnSerializationFunc = nullptr; + void* m_pUserData = nullptr; + bool m_bPretty = true; + std::string m_osIndent = std::string(" "); + std::string m_osIndentAcc{}; + int m_nLevel = 0; + bool m_bNewLineEnabled = true; + struct State + { + bool bIsObj = false; + bool bFirstChild = true; + explicit State(bool bIsObjIn): bIsObj(bIsObjIn) {} + }; + std::vector m_states{}; + bool m_bWaitForValue = false; + + void Print(const std::string& text); + void IncIndent(); + void DecIndent(); + static std::string FormatString(const std::string& str); + void EmitCommaIfNeeded(); + +public: + CPLJSonStreamingWriter(SerializationFuncType pfnSerializationFunc, + void* pUserData); + ~CPLJSonStreamingWriter(); + + void SetPrettyFormatting(bool bPretty) { m_bPretty = bPretty; } + void SetIndentationSize(int nSpaces); + + // cppcheck-suppress functionStatic + const std::string& GetString() const { return m_osStr; } + + void Add(const std::string& str); + void Add(const char* pszStr); + void Add(bool bVal); + void Add(int nVal) { Add(static_cast(nVal)); } + void Add(unsigned int nVal) { Add(static_cast(nVal)); } + void Add(GIntBig nVal); + void Add(GUInt64 nVal); + void Add(float fVal, int nPrecision = 9); + void Add(double dfVal, int nPrecision = 18); + void AddNull(); + + void StartObj(); + void EndObj(); + void AddObjKey(const std::string& key); + struct CPL_DLL ObjectContext + { + CPLJSonStreamingWriter& m_serializer; + explicit ObjectContext(CPLJSonStreamingWriter& serializer): + m_serializer(serializer) { m_serializer.StartObj(); } + ~ObjectContext() { m_serializer.EndObj(); } + }; + + void StartArray(); + void EndArray(); + struct CPL_DLL ArrayContext + { + CPLJSonStreamingWriter& m_serializer; + bool m_bForceSingleLine; + bool m_bNewLineEnabledBackup; + + ArrayContext(CPLJSonStreamingWriter& serializer, + bool bForceSingleLine = false): + m_serializer(serializer), + m_bForceSingleLine(bForceSingleLine), + m_bNewLineEnabledBackup(serializer.GetNewLine()) + { + if( m_bForceSingleLine ) + serializer.SetNewline(false); + m_serializer.StartArray(); + + } + ~ArrayContext() + { + m_serializer.EndArray(); + if( m_bForceSingleLine ) + m_serializer.SetNewline(m_bNewLineEnabledBackup); + } + }; + + bool GetNewLine() const { return m_bNewLineEnabled; } + void SetNewline(bool bEnabled) { m_bNewLineEnabled = bEnabled; } +}; + +} // namespace PROJ + +/*! @endcond */ + +#endif // PROJ_JSON_STREAMING_WRITER_H diff --git a/test/unit/test_datum.cpp b/test/unit/test_datum.cpp index fa53ff855b..121b7c88ca 100644 --- a/test/unit/test_datum.cpp +++ b/test/unit/test_datum.cpp @@ -205,6 +205,34 @@ TEST(datum, prime_meridian_to_PROJString) { // --------------------------------------------------------------------------- +TEST(datum, prime_meridian_to_JSON) { + + EXPECT_EQ( + PrimeMeridian::GREENWICH->exportToJSON(JSONFormatter::create().get()), + "{\n" + " \"type\": \"PrimeMeridian\",\n" + " \"name\": \"Greenwich\",\n" + " \"longitude\": {\n" + " \"value\": 0,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"degree\",\n" + " \"conversion_factor\": 0.0174532925199433,\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 9122\n" + " }\n" + " }\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8901\n" + " }\n" + "}"); +} + +// --------------------------------------------------------------------------- + TEST(datum, datum_with_ANCHOR) { auto datum = GeodeticReferenceFrame::create( PropertyMap().set(IdentifiedObject::NAME_KEY, "WGS_1984 with anchor"), From ece151aed1b4bf2634de5759f37fd7bc005e8313 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 6 Jul 2019 17:06:23 +0200 Subject: [PATCH 02/16] CRS JSON: export GeographicCRS and Projected CRS --- include/proj/common.hpp | 11 +- include/proj/coordinateoperation.hpp | 19 ++- include/proj/coordinatesystem.hpp | 13 +- include/proj/crs.hpp | 21 +++- include/proj/datum.hpp | 12 +- include/proj/io.hpp | 21 +++- scripts/reference_exported_symbols.txt | 3 + src/apps/projinfo.cpp | 33 ++++- src/iso19111/common.cpp | 84 ++++++++++++- src/iso19111/coordinateoperation.cpp | 85 +++++++++++++ src/iso19111/coordinatesystem.cpp | 59 ++++++++- src/iso19111/crs.cpp | 160 +++++++++++++++++++++++++ src/iso19111/datum.cpp | 106 +++++++++++++++- src/iso19111/io.cpp | 61 +++++++++- src/iso19111/metadata.cpp | 2 +- src/proj_json_streaming_writer.cpp | 5 +- src/proj_json_streaming_writer.hpp | 20 +++- test/cli/testprojinfo_out.dist | 74 ++++++++++++ test/unit/test_datum.cpp | 6 +- 19 files changed, 753 insertions(+), 42 deletions(-) diff --git a/include/proj/common.hpp b/include/proj/common.hpp index d857dafdd9..0a1f5d19b4 100644 --- a/include/proj/common.hpp +++ b/include/proj/common.hpp @@ -330,10 +330,13 @@ class PROJ_GCC_DLL IdentifiedObject : public util::BaseObject, //! @cond Doxygen_Suppress void formatID(io::WKTFormatter *formatter) const; - PROJ_INTERNAL void formatRemarks(io::WKTFormatter *formatter) const; PROJ_INTERNAL void formatID(io::JSONFormatter *formatter) const; + PROJ_INTERNAL void formatRemarks(io::WKTFormatter *formatter) const; + + PROJ_INTERNAL void formatRemarks(io::JSONFormatter *formatter) const; + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -394,6 +397,9 @@ class PROJ_GCC_DLL ObjectDomain : public util::BaseObject, _exportToWKT(io::WKTFormatter *formatter) const; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON( + io::JSONFormatter *formatter) const; // throw(FormattingException) + bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -455,6 +461,9 @@ class PROJ_GCC_DLL ObjectUsage : public IdentifiedObject { void baseExportToWKT( io::WKTFormatter *formatter) const; // throw(io::FormattingException) + void baseExportToJSON( + io::JSONFormatter *formatter) const; // throw(io::FormattingException) + private: PROJ_OPAQUE_PRIVATE_DATA ObjectUsage &operator=(const ObjectUsage &other) = delete; diff --git a/include/proj/coordinateoperation.hpp b/include/proj/coordinateoperation.hpp index 7ade26f2b7..9b2dfe6430 100644 --- a/include/proj/coordinateoperation.hpp +++ b/include/proj/coordinateoperation.hpp @@ -291,6 +291,7 @@ struct MethodMapping; */ class PROJ_GCC_DLL GeneralParameterValue : public util::BaseObject, public io::IWKTExportable, + public io::IJSONExportable, public util::IComparable { public: //! @cond Doxygen_Suppress @@ -299,6 +300,9 @@ class PROJ_GCC_DLL GeneralParameterValue : public util::BaseObject, PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override = 0; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override = 0; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion = @@ -442,6 +446,9 @@ class PROJ_GCC_DLL OperationParameterValue final PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -481,7 +488,8 @@ using OperationMethodNNPtr = util::nn; * * \remark Implements OperationMethod from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL OperationMethod : public common::IdentifiedObject { +class PROJ_GCC_DLL OperationMethod : public common::IdentifiedObject, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~OperationMethod() override; @@ -507,6 +515,9 @@ class PROJ_GCC_DLL OperationMethod : public common::IdentifiedObject { PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -838,7 +849,8 @@ EPSG:8833 */ -class PROJ_GCC_DLL Conversion : public SingleOperation { +class PROJ_GCC_DLL Conversion : public SingleOperation, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~Conversion() override; @@ -1315,6 +1327,9 @@ class PROJ_GCC_DLL Conversion : public SingleOperation { _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL const char *getESRIMethodName() const; PROJ_INTERNAL const char *getWKT1GDALMethodName() const; diff --git a/include/proj/coordinatesystem.hpp b/include/proj/coordinatesystem.hpp index ea1c1f9933..ffb908fc6e 100644 --- a/include/proj/coordinatesystem.hpp +++ b/include/proj/coordinatesystem.hpp @@ -165,8 +165,8 @@ using CoordinateSystemAxisNNPtr = util::nn; * * \remark Implements CoordinateSystemAxis from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL CoordinateSystemAxis final - : public common::IdentifiedObject { +class PROJ_GCC_DLL CoordinateSystemAxis final : public common::IdentifiedObject, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~CoordinateSystemAxis() override; @@ -201,6 +201,9 @@ class PROJ_GCC_DLL CoordinateSystemAxis final PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL static std::string normalizeAxisName(const std::string &str); PROJ_INTERNAL static CoordinateSystemAxisNNPtr @@ -235,7 +238,8 @@ class PROJ_GCC_DLL CoordinateSystemAxis final * * \remark Implements CoordinateSystem from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL CoordinateSystem : public common::IdentifiedObject { +class PROJ_GCC_DLL CoordinateSystem : public common::IdentifiedObject, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~CoordinateSystem() override; @@ -251,6 +255,9 @@ class PROJ_GCC_DLL CoordinateSystem : public common::IdentifiedObject { _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL virtual std::string getWKT2Type(bool) const = 0; PROJ_INTERNAL bool diff --git a/include/proj/crs.hpp b/include/proj/crs.hpp index 33bf3b6176..702b2d3632 100644 --- a/include/proj/crs.hpp +++ b/include/proj/crs.hpp @@ -211,7 +211,8 @@ using GeodeticCRSNNPtr = util::nn; * \remark Implements GeodeticCRS from \ref ISO_19111_2019 */ class PROJ_GCC_DLL GeodeticCRS : virtual public SingleCRS, - public io::IPROJStringExportable { + public io::IPROJStringExportable, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~GeodeticCRS() override; @@ -273,6 +274,9 @@ class PROJ_GCC_DLL GeodeticCRS : virtual public SingleCRS, PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -353,6 +357,9 @@ class PROJ_GCC_DLL GeographicCRS : public GeodeticCRS { PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_DLL bool is2DPartOf3D(util::nn other) PROJ_PURE_DECL; @@ -546,7 +553,8 @@ using ProjectedCRSNNPtr = util::nn; * \remark Implements ProjectedCRS from \ref ISO_19111_2019 */ class PROJ_GCC_DLL ProjectedCRS final : public DerivedCRS, - public io::IPROJStringExportable { + public io::IPROJStringExportable, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~ProjectedCRS() override; @@ -573,6 +581,9 @@ class PROJ_GCC_DLL ProjectedCRS final : public DerivedCRS, PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_FOR_TEST ProjectedCRSNNPtr alterParametersLinearUnit( const common::UnitOfMeasure &unit, bool convertToNewUnit) const; @@ -965,6 +976,9 @@ class PROJ_GCC_DLL DerivedGeodeticCRS final : public GeodeticCRS, //! @cond Doxygen_Suppress void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) //! @endcond protected: @@ -1034,6 +1048,9 @@ class PROJ_GCC_DLL DerivedGeographicCRS final : public GeographicCRS, //! @cond Doxygen_Suppress PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) //! @endcond protected: diff --git a/include/proj/datum.hpp b/include/proj/datum.hpp index 47bab4a07b..00e56a1cdc 100644 --- a/include/proj/datum.hpp +++ b/include/proj/datum.hpp @@ -247,7 +247,8 @@ using EllipsoidNNPtr = util::nn; * \remark Implements Ellipsoid from \ref ISO_19111_2019 */ class PROJ_GCC_DLL Ellipsoid final : public common::IdentifiedObject, - public io::IPROJStringExportable { + public io::IPROJStringExportable, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~Ellipsoid() override; @@ -304,6 +305,9 @@ class PROJ_GCC_DLL Ellipsoid final : public common::IdentifiedObject, _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(io::FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -375,7 +379,8 @@ using GeodeticReferenceFrameNNPtr = util::nn; * * \remark Implements GeodeticReferenceFrame from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL GeodeticReferenceFrame : public Datum { +class PROJ_GCC_DLL GeodeticReferenceFrame : public Datum, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~GeodeticReferenceFrame() override; @@ -403,6 +408,9 @@ class PROJ_GCC_DLL GeodeticReferenceFrame : public Datum { PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = diff --git a/include/proj/io.hpp b/include/proj/io.hpp index 71a6430d7b..cfb4b3f783 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -483,12 +483,31 @@ class PROJ_GCC_DLL JSONFormatter { PROJ_PRIVATE : //! @cond Doxygen_Suppress - PROJ_INTERNAL PROJ::CPLJSonStreamingWriter & + PROJ_INTERNAL CPLJSonStreamingWriter & writer() const; + struct ObjectContext { + JSONFormatter &m_formatter; + + ObjectContext(const ObjectContext &) = delete; + ObjectContext(ObjectContext &&) = default; + + explicit ObjectContext(JSONFormatter &formatter, const char *objectType, + bool hasId); + ~ObjectContext(); + }; + PROJ_INTERNAL inline ObjectContext MakeObjectContext(const char *objectType, + bool hasId) { + return ObjectContext(*this, objectType, hasId); + } + + PROJ_INTERNAL void setAllowIDInImmediateChild(); + // cppcheck-suppress functionStatic PROJ_INTERNAL bool outputId() const; + PROJ_INTERNAL bool outputUsage() const; + //! @endcond protected: diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index 51ef425abb..dc1e1efdd4 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -67,6 +67,7 @@ osgeo::proj::common::ObjectDomain::~ObjectDomain() osgeo::proj::common::ObjectDomain::ObjectDomain(osgeo::proj::common::ObjectDomain const&) osgeo::proj::common::ObjectDomain::ObjectDomain(osgeo::proj::util::optional const&, std::shared_ptr const&) osgeo::proj::common::ObjectDomain::scope() const +osgeo::proj::common::ObjectUsage::baseExportToJSON(osgeo::proj::io::JSONFormatter*) const osgeo::proj::common::ObjectUsage::baseExportToWKT(osgeo::proj::io::WKTFormatter*) const osgeo::proj::common::ObjectUsage::domains() const osgeo::proj::common::ObjectUsage::_isEquivalentTo(osgeo::proj::util::IComparable const*, osgeo::proj::util::IComparable::Criterion) const @@ -339,6 +340,8 @@ osgeo::proj::io::IWKTExportable::exportToWKT(osgeo::proj::io::WKTFormatter*) con osgeo::proj::io::IWKTExportable::~IWKTExportable() osgeo::proj::io::JSONFormatter::create(std::shared_ptr) osgeo::proj::io::JSONFormatter::~JSONFormatter() +osgeo::proj::io::JSONFormatter::ObjectContext::~ObjectContext() +osgeo::proj::io::JSONFormatter::ObjectContext::ObjectContext(osgeo::proj::io::JSONFormatter&, char const*, bool) osgeo::proj::io::JSONFormatter::setIndentationWidth(int) osgeo::proj::io::JSONFormatter::setMultiLine(bool) osgeo::proj::io::JSONFormatter::toString() const diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 9d724522f8..6b1267e00e 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -67,6 +67,7 @@ struct OutputOptions { bool WKT2_2015_SIMPLIFIED = false; bool WKT1_GDAL = false; bool WKT1_ESRI = false; + bool JSON = false; bool c_ify = false; bool singleLine = false; bool strict = true; @@ -101,7 +102,7 @@ static void usage() { std::cerr << std::endl; std::cerr << "-o: formats is a comma separated combination of: " "all,default,PROJ,WKT_ALL,WKT2_2015,WKT2_2018,WKT1_GDAL," - "WKT1_ESRI" + "WKT1_ESRI,JSON" << std::endl; std::cerr << " Except 'all' and 'default', other format can be preceded " "by '-' to disable them" @@ -467,6 +468,29 @@ static void outputObject( std::cerr << "Error when exporting to WKT1_ESRI: " << e.what() << std::endl; } + alreadyOutputed = true; + } + } + + auto JSONExportable = nn_dynamic_pointer_cast(obj); + if (JSONExportable) { + if (outputOpt.JSON) { + try { + if (alreadyOutputed) { + std::cout << std::endl; + } + if (!outputOpt.quiet) { + std::cout << "JSON:" << std::endl; + } + + std::cout << JSONExportable->exportToJSON( + JSONFormatter::create(dbContext).get()) + << std::endl; + } catch (const std::exception &e) { + std::cerr << "Error when exporting to JSON: " << e.what() + << std::endl; + } + // alreadyOutputed = true; } } @@ -720,6 +744,7 @@ int main(int argc, char **argv) { outputOpt.WKT2_2015 = true; outputOpt.WKT1_GDAL = true; outputOpt.WKT1_ESRI = true; + outputOpt.JSON = true; } else if (ci_equal(format, "default")) { outputOpt.PROJ5 = true; outputOpt.WKT2_2018 = true; @@ -779,6 +804,10 @@ int main(int argc, char **argv) { ci_equal(format, "-WKT1-ESRI") || ci_equal(format, "-WKT1:ESRI")) { outputOpt.WKT1_ESRI = false; + } else if (ci_equal(format, "JSON")) { + outputOpt.JSON = true; + } else if (ci_equal(format, "-JSON")) { + outputOpt.JSON = false; } else { std::cerr << "Unrecognized value for option -o: " << format << std::endl; @@ -998,7 +1027,7 @@ int main(int argc, char **argv) { if (outputOpt.quiet && (outputOpt.PROJ5 + outputOpt.WKT2_2018 + outputOpt.WKT2_2015 + - outputOpt.WKT1_GDAL) != 1) { + outputOpt.WKT1_GDAL + outputOpt.JSON) != 1) { std::cerr << "-q can only be used with a single output format" << std::endl; usage(); diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp index f2a510323b..fb7a63c08e 100644 --- a/src/iso19111/common.cpp +++ b/src/iso19111/common.cpp @@ -243,7 +243,9 @@ void UnitOfMeasure::_exportToJSON( JSONFormatter *formatter) const // throw(FormattingException) { auto &writer = formatter->writer(); - PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer); + const auto &l_codeSpace = codeSpace(); + auto objContext( + formatter->MakeObjectContext(nullptr, !l_codeSpace.empty())); writer.AddObjKey("type"); const auto l_type = type(); if (l_type == Type::LINEAR) { @@ -268,10 +270,9 @@ void UnitOfMeasure::_exportToJSON( writer.AddObjKey("conversion_factor"); writer.Add(factor, 15); - const auto &l_codeSpace = codeSpace(); if (!l_codeSpace.empty() && formatter->outputId()) { writer.AddObjKey("id"); - PROJ::CPLJSonStreamingWriter::ObjectContext idContext(writer); + auto idContext(formatter->MakeObjectContext(nullptr, false)); writer.AddObjKey("authority"); writer.Add(l_codeSpace); writer.AddObjKey("code"); @@ -871,7 +872,7 @@ void IdentifiedObject::formatID(JSONFormatter *formatter) const { ids.front()->_exportToJSON(formatter); } else if (!ids.empty()) { writer.AddObjKey("ids"); - PROJ::CPLJSonStreamingWriter::ArrayContext arrayContext(writer); + auto arrayContext(writer.MakeArrayContext()); for (const auto &id : ids) { id->_exportToJSON(formatter); } @@ -880,6 +881,16 @@ void IdentifiedObject::formatID(JSONFormatter *formatter) const { // --------------------------------------------------------------------------- +void IdentifiedObject::formatRemarks(JSONFormatter *formatter) const { + if (!remarks().empty()) { + auto &writer = formatter->writer(); + writer.AddObjKey("remarks"); + writer.Add(remarks()); + } +} + +// --------------------------------------------------------------------------- + bool IdentifiedObject::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion) const { @@ -1030,6 +1041,46 @@ void ObjectDomain::_exportToWKT(WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void ObjectDomain::_exportToJSON(JSONFormatter *formatter) const { + auto &writer = formatter->writer(); + if (d->scope_.has_value()) { + writer.AddObjKey("scope"); + writer.Add(*(d->scope_)); + } + if (d->domainOfValidity_) { + if (d->domainOfValidity_->description().has_value()) { + writer.AddObjKey("area"); + writer.Add(*(d->domainOfValidity_->description())); + } + if (d->domainOfValidity_->geographicElements().size() == 1) { + const auto bbox = dynamic_cast( + d->domainOfValidity_->geographicElements()[0].get()); + if (bbox) { + writer.AddObjKey("bbox"); + auto bboxContext(writer.MakeObjectContext()); + writer.AddObjKey("south_latitude"); + writer.Add(bbox->southBoundLatitude(), 15); + writer.AddObjKey("west_longitude"); + writer.Add(bbox->westBoundLongitude(), 15); + writer.AddObjKey("north_latitude"); + writer.Add(bbox->northBoundLatitude(), 15); + writer.AddObjKey("east_longitude"); + writer.Add(bbox->eastBoundLongitude(), 15); + } + } + if (d->domainOfValidity_->verticalElements().size() == 1) { + // TODO + } + if (d->domainOfValidity_->temporalElements().size() == 1) { + // TODO + } + } +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool ObjectDomain::_isEquivalentTo( const util::IComparable *other, @@ -1162,6 +1213,31 @@ void ObjectUsage::baseExportToWKT(WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +void ObjectUsage::baseExportToJSON(JSONFormatter *formatter) const { + + auto &writer = formatter->writer(); + if (formatter->outputUsage()) { + const auto &l_domains = domains(); + if (l_domains.size() == 1) { + l_domains[0]->_exportToJSON(formatter); + } else if (!l_domains.empty()) { + writer.AddObjKey("usages"); + auto arrayContext(writer.MakeArrayContext(false)); + for (const auto &domain : l_domains) { + auto objContext(writer.MakeObjectContext()); + domain->_exportToJSON(formatter); + } + } + } + + if (formatter->outputId()) { + formatID(formatter); + } + formatRemarks(formatter); +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool ObjectUsage::_isEquivalentTo( const util::IComparable *other, diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 7f3a213775..a2a31edd93 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -990,6 +990,24 @@ void OperationMethod::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void OperationMethod::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext("OperationMethod", + !identifiers().empty())); + + writer.AddObjKey("name"); + writer.Add(nameStr()); + + if (formatter->outputId()) { + formatID(formatter); + } +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool OperationMethod::_isEquivalentTo( const util::IComparable *other, @@ -1167,6 +1185,35 @@ void OperationParameterValue::_exportToWKT(io::WKTFormatter *formatter, // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void OperationParameterValue::_exportToJSON( + io::JSONFormatter *formatter) const { + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext( + "ParameterValue", !parameter()->identifiers().empty())); + + writer.AddObjKey("name"); + writer.Add(parameter()->nameStr()); + + const auto &l_value(parameterValue()); + if (l_value->type() == ParameterValue::Type::MEASURE) { + writer.AddObjKey("value"); + writer.Add(l_value->value().value(), 15); + writer.AddObjKey("unit"); + l_value->value().unit()._exportToJSON(formatter); + } else if (l_value->type() == ParameterValue::Type::FILENAME) { + writer.AddObjKey("value"); + writer.Add(l_value->valueFile()); + } + + if (formatter->outputId()) { + parameter()->formatID(formatter); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress /** Utility method used on WKT2 import to convert from abridged transformation @@ -5409,6 +5456,44 @@ void Conversion::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void Conversion::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("Conversion", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("method"); + formatter->setAllowIDInImmediateChild(); + method()->_exportToJSON(formatter); + + writer.AddObjKey("parameters"); + { + auto parametersContext(writer.MakeArrayContext(false)); + for (const auto &genOpParamvalue : parameterValues()) { + formatter->setAllowIDInImmediateChild(); + genOpParamvalue->_exportToJSON(formatter); + } + } + + if (formatter->outputId()) { + formatID(formatter); + } +} + +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress static bool createPROJ4WebMercator(const Conversion *conv, io::PROJStringFormatter *formatter) { diff --git a/src/iso19111/coordinatesystem.cpp b/src/iso19111/coordinatesystem.cpp index ef9cac9346..f96a962fb5 100644 --- a/src/iso19111/coordinatesystem.cpp +++ b/src/iso19111/coordinatesystem.cpp @@ -311,8 +311,8 @@ void CoordinateSystemAxis::_exportToWKT(io::WKTFormatter *formatter, int order, bool disableAbbrev) const { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; formatter->startNode(io::WKTConstants::AXIS, !identifiers().empty()); - std::string axisName = *(name()->description()); - std::string abbrev = abbreviation(); + const std::string &axisName = nameStr(); + const std::string &abbrev = abbreviation(); std::string parenthesizedAbbrev = "(" + abbrev + ")"; std::string dir = direction().toString(); std::string axisDesignation; @@ -392,6 +392,34 @@ void CoordinateSystemAxis::_exportToWKT(io::WKTFormatter *formatter, int order, // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void CoordinateSystemAxis::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("Axis", !identifiers().empty())); + + writer.AddObjKey("name"); + writer.Add(nameStr()); + + writer.AddObjKey("abbreviation"); + writer.Add(abbreviation()); + + writer.AddObjKey("direction"); + writer.Add(direction().toString()); + + writer.AddObjKey("unit"); + unit()._exportToJSON(formatter); + + if (formatter->outputId()) { + formatID(formatter); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool CoordinateSystemAxis::_isEquivalentTo( const util::IComparable *other, @@ -534,6 +562,33 @@ void CoordinateSystem::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void CoordinateSystem::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext("CoordinateSystem", + !identifiers().empty())); + + writer.AddObjKey("subtype"); + writer.Add(getWKT2Type(true)); + + writer.AddObjKey("axis"); + auto axisContext(writer.MakeArrayContext(false)); + const auto &l_axisList = axisList(); + for (auto &axis : l_axisList) { + axis->_exportToJSON(formatter); + } + + if (formatter->outputId()) { + formatID(formatter); + } +} + +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool CoordinateSystem::_isEquivalentTo( const util::IComparable *other, diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 476bc72b1d..2ca2786d1f 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -1341,6 +1341,39 @@ void GeodeticCRS::addDatumInfoToPROJString( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void GeodeticCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("GeodeticCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + const auto &l_datum(datum()); + if (l_datum) { + writer.AddObjKey("datum"); + l_datum->_exportToJSON(formatter); + } else { + // TODO DatumEnsemble + } + + writer.AddObjKey("coordinate_system"); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress static util::IComparable::Criterion getStandardCriterion(util::IComparable::Criterion criterion) { @@ -2058,6 +2091,39 @@ void GeographicCRS::_exportToPROJString( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void GeographicCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("GeographicCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + const auto &l_datum(datum()); + if (l_datum) { + writer.AddObjKey("datum"); + l_datum->_exportToJSON(formatter); + } else { + // TODO DatumEnsemble + } + + writer.AddObjKey("coordinate_system"); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress struct VerticalCRS::Private { std::vector geoidModel{}; @@ -2856,6 +2922,38 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void ProjectedCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("ProjectedCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("base_crs"); + formatter->setAllowIDInImmediateChild(); + baseCRS()->_exportToJSON(formatter); + + writer.AddObjKey("conversion"); + derivingConversionRef()->_exportToJSON(formatter); + + writer.AddObjKey("coordinate_system"); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + void ProjectedCRS::_exportToPROJString( io::PROJStringFormatter *formatter) const // throw(io::FormattingException) { @@ -4195,6 +4293,37 @@ void DerivedGeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void DerivedGeodeticCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext("DerivedGeodeticCRS", + !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("base_crs"); + baseCRS()->_exportToJSON(formatter); + + writer.AddObjKey("conversion"); + derivingConversionRef()->_exportToJSON(formatter); + + writer.AddObjKey("coordinate_system"); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + void DerivedGeodeticCRS::_exportToPROJString( io::PROJStringFormatter *) const // throw(io::FormattingException) { @@ -4333,6 +4462,37 @@ void DerivedGeographicCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void DerivedGeographicCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext("DerivedGeographicCRS", + !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("base_crs"); + baseCRS()->_exportToJSON(formatter); + + writer.AddObjKey("conversion"); + derivingConversionRef()->_exportToJSON(formatter); + + writer.AddObjKey("coordinate_system"); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + void DerivedGeographicCRS::_exportToPROJString( io::PROJStringFormatter *) const // throw(io::FormattingException) { diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 6ba219d4ec..89ecc7556d 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -93,6 +93,9 @@ struct Datum::Private { // cppcheck-suppress functionStatic void exportAnchorDefinition(io::WKTFormatter *formatter) const; + + // cppcheck-suppress functionStatic + void exportAnchorDefinition(io::JSONFormatter *formatter) const; }; // --------------------------------------------------------------------------- @@ -105,6 +108,17 @@ void Datum::Private::exportAnchorDefinition(io::WKTFormatter *formatter) const { } } +// --------------------------------------------------------------------------- + +void Datum::Private::exportAnchorDefinition( + io::JSONFormatter *formatter) const { + if (anchorDefinition) { + auto &writer = formatter->writer(); + writer.AddObjKey("anchor"); + writer.Add(*anchorDefinition); + } +} + //! @endcond // --------------------------------------------------------------------------- @@ -352,10 +366,8 @@ void PrimeMeridian::_exportToJSON( io::JSONFormatter *formatter) const // throw(FormattingException) { auto &writer = formatter->writer(); - PROJ::CPLJSonStreamingWriter::ObjectContext objectContext(writer); - - writer.AddObjKey("type"); - writer.Add("PrimeMeridian"); + auto objectContext( + formatter->MakeObjectContext("PrimeMeridian", !identifiers().empty())); writer.AddObjKey("name"); std::string l_name = @@ -365,7 +377,7 @@ void PrimeMeridian::_exportToJSON( const auto &l_long = longitude(); writer.AddObjKey("longitude"); { - PROJ::CPLJSonStreamingWriter::ObjectContext longitudeContext(writer); + auto longitudeContext(formatter->MakeObjectContext(nullptr, false)); writer.AddObjKey("value"); writer.Add(l_long.value(), 15); @@ -803,6 +815,60 @@ void Ellipsoid::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void Ellipsoid::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("Ellipsoid", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + const auto &semiMajor = semiMajorAxis(); + const auto &semiMajorUnit = semiMajor.unit(); + writer.AddObjKey(isSphere() ? "radius" : "semi_major_axis"); + { + auto objContext(formatter->MakeObjectContext(nullptr, false)); + writer.AddObjKey("value"); + writer.Add(semiMajor.value(), 15); + + writer.AddObjKey("unit"); + semiMajorUnit._exportToJSON(formatter); + } + + if (!isSphere()) { + const auto &l_inverseFlattening = inverseFlattening(); + if (l_inverseFlattening.has_value()) { + writer.AddObjKey("inverse_flattening"); + writer.Add(l_inverseFlattening->getSIValue(), 15); + } else { + writer.AddObjKey("semi_minor_axis"); + { + auto objContext(formatter->MakeObjectContext(nullptr, false)); + writer.AddObjKey("value"); + writer.Add(semiMinorAxis()->value(), 15); + + writer.AddObjKey("unit"); + semiMinorAxis()->unit()._exportToJSON(formatter); + } + } + } + + if (formatter->outputId()) { + formatID(formatter); + } +} +//! @endcond + +// --------------------------------------------------------------------------- + bool Ellipsoid::lookForProjWellKnownEllps(std::string &projEllpsName, std::string &ellpsName) const { const double a = semiMajorAxis().getSIValue(); @@ -1187,6 +1253,36 @@ void GeodeticReferenceFrame::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void GeodeticReferenceFrame::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto objectContext(formatter->MakeObjectContext("GeodeticReferenceFrame", + !identifiers().empty())); + auto &writer = formatter->writer(); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + Datum::getPrivate()->exportAnchorDefinition(formatter); + + writer.AddObjKey("ellipsoid"); + ellipsoid()->_exportToJSON(formatter); + + writer.AddObjKey("prime_meridian"); + primeMeridian()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool GeodeticReferenceFrame::_isEquivalentTo( const util::IComparable *other, diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 0c9f8a0ca7..35798d9d77 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -8021,9 +8021,20 @@ PROJStringParser::createFromPROJString(const std::string &projString) { //! @cond Doxygen_Suppress struct JSONFormatter::Private { - PROJ::CPLJSonStreamingWriter writer_{nullptr, nullptr}; + CPLJSonStreamingWriter writer_{nullptr, nullptr}; DatabaseContextPtr dbContext_{}; + + std::vector stackHasId_{false}; + std::vector outputIdStack_{true}; + bool allowIDInImmediateChild_ = false; + std::string result_{}; + + // cppcheck-suppress functionStatic + void pushOutputId(bool outputIdIn) { outputIdStack_.push_back(outputIdIn); } + + // cppcheck-suppress functionStatic + void popOutputId() { outputIdStack_.pop_back(); } }; //! @endcond @@ -8071,13 +8082,55 @@ JSONFormatter::~JSONFormatter() = default; // --------------------------------------------------------------------------- -PROJ::CPLJSonStreamingWriter &JSONFormatter::writer() const { - return d->writer_; +CPLJSonStreamingWriter &JSONFormatter::writer() const { return d->writer_; } + +// --------------------------------------------------------------------------- + +bool JSONFormatter::outputId() const { return d->outputIdStack_.back(); } + +// --------------------------------------------------------------------------- + +bool JSONFormatter::outputUsage() const { + return outputId() && d->outputIdStack_.size() == 2; } // --------------------------------------------------------------------------- -bool JSONFormatter::outputId() const { return true; } +void JSONFormatter::setAllowIDInImmediateChild() { + d->allowIDInImmediateChild_ = true; +} + +// --------------------------------------------------------------------------- + +JSONFormatter::ObjectContext::ObjectContext(JSONFormatter &formatter, + const char *objectType, bool hasId) + : m_formatter(formatter) { + m_formatter.d->writer_.StartObj(); + if (objectType) { + m_formatter.d->writer_.AddObjKey("type"); + m_formatter.d->writer_.Add(objectType); + } + // All intermediate nodes shouldn't have ID if a parent has an ID + // unless explicitly enabled. + if (m_formatter.d->allowIDInImmediateChild_) { + m_formatter.d->pushOutputId(m_formatter.d->outputIdStack_[0]); + m_formatter.d->allowIDInImmediateChild_ = false; + } else { + m_formatter.d->pushOutputId(m_formatter.d->outputIdStack_[0] && + !m_formatter.d->stackHasId_.back()); + } + + m_formatter.d->stackHasId_.push_back(hasId || + m_formatter.d->stackHasId_.back()); +} + +// --------------------------------------------------------------------------- + +JSONFormatter::ObjectContext::~ObjectContext() { + m_formatter.d->writer_.EndObj(); + m_formatter.d->stackHasId_.pop_back(); + m_formatter.d->popOutputId(); +} //! @endcond diff --git a/src/iso19111/metadata.cpp b/src/iso19111/metadata.cpp index 761b909b41..41653b3242 100644 --- a/src/iso19111/metadata.cpp +++ b/src/iso19111/metadata.cpp @@ -1096,7 +1096,7 @@ void Identifier::_exportToJSON(JSONFormatter *formatter) const { const std::string &l_codeSpace = *codeSpace(); if (!l_codeSpace.empty() && !l_code.empty()) { auto &writer = formatter->writer(); - PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer); + auto objContext(formatter->MakeObjectContext(nullptr, false)); writer.AddObjKey("authority"); writer.Add(l_codeSpace); writer.AddObjKey("code"); diff --git a/src/proj_json_streaming_writer.cpp b/src/proj_json_streaming_writer.cpp index 3198308bd2..4a9b9bd2fe 100644 --- a/src/proj_json_streaming_writer.cpp +++ b/src/proj_json_streaming_writer.cpp @@ -56,8 +56,7 @@ static std::string CPLSPrintf(const char* fmt, ...) return res; } -namespace PROJ -{ +NS_PROJ_START CPLJSonStreamingWriter::CPLJSonStreamingWriter( SerializationFuncType pfnSerializationFunc, @@ -292,6 +291,6 @@ void CPLJSonStreamingWriter::AddNull() Print("null"); } -} // namespace PROJ +NS_PROJ_END /*! @endcond */ diff --git a/src/proj_json_streaming_writer.hpp b/src/proj_json_streaming_writer.hpp index d151044958..6267684218 100644 --- a/src/proj_json_streaming_writer.hpp +++ b/src/proj_json_streaming_writer.hpp @@ -36,8 +36,8 @@ #define CPL_DLL -namespace PROJ -{ +#include "proj/util.hpp" +NS_PROJ_START typedef std::int64_t GIntBig; typedef std::uint64_t GUInt64; @@ -102,10 +102,15 @@ class CPL_DLL CPLJSonStreamingWriter struct CPL_DLL ObjectContext { CPLJSonStreamingWriter& m_serializer; - explicit ObjectContext(CPLJSonStreamingWriter& serializer): + + ObjectContext(const ObjectContext &) = delete; + ObjectContext(ObjectContext&&) = default; + + explicit inline ObjectContext(CPLJSonStreamingWriter& serializer): m_serializer(serializer) { m_serializer.StartObj(); } ~ObjectContext() { m_serializer.EndObj(); } }; + inline ObjectContext MakeObjectContext() { return ObjectContext(*this); } void StartArray(); void EndArray(); @@ -115,7 +120,10 @@ class CPL_DLL CPLJSonStreamingWriter bool m_bForceSingleLine; bool m_bNewLineEnabledBackup; - ArrayContext(CPLJSonStreamingWriter& serializer, + ArrayContext(const ArrayContext &) = delete; + ArrayContext(ArrayContext&&) = default; + + inline explicit ArrayContext(CPLJSonStreamingWriter& serializer, bool bForceSingleLine = false): m_serializer(serializer), m_bForceSingleLine(bForceSingleLine), @@ -133,12 +141,14 @@ class CPL_DLL CPLJSonStreamingWriter m_serializer.SetNewline(m_bNewLineEnabledBackup); } }; + inline ArrayContext MakeArrayContext(bool bForceSingleLine = false) + { return ArrayContext(*this, bForceSingleLine); } bool GetNewLine() const { return m_bNewLineEnabled; } void SetNewline(bool bEnabled) { m_bNewLineEnabled = bEnabled; } }; -} // namespace PROJ +NS_PROJ_END /*! @endcond */ diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index f742fa6086..20ae544aeb 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -135,6 +135,80 @@ WKT1_ESRI: GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] +JSON: +{ + "type": "GeographicCRS", + "name": "WGS 84", + "datum": { + "type": "GeodeticReferenceFrame", + "name": "World Geodetic System 1984", + "ellipsoid": { + "type": "Ellipsoid", + "name": "WGS 84", + "semi_major_axis": { + "value": 6378137, + "unit": { + "type": "LinearUnit", + "name": "metre", + "conversion_factor": 1 + } + }, + "inverse_flattening": 298.257223563 + }, + "prime_meridian": { + "type": "PrimeMeridian", + "name": "Greenwich", + "longitude": { + "value": 0, + "unit": { + "type": "AngularUnit", + "name": "degree", + "conversion_factor": 0.0174532925199433 + } + } + } + }, + "coordinate_system": { + "type": "CoordinateSystem", + "subtype": "ellipsoidal", + "axis": [ + { + "type": "Axis", + "name": "Geodetic latitude", + "abbreviation": "Lat", + "direction": "north", + "unit": { + "type": "AngularUnit", + "name": "degree", + "conversion_factor": 0.0174532925199433 + } + }, + { + "type": "Axis", + "name": "Geodetic longitude", + "abbreviation": "Lon", + "direction": "east", + "unit": { + "type": "AngularUnit", + "name": "degree", + "conversion_factor": 0.0174532925199433 + } + } + ] + }, + "area": "World", + "bbox": { + "south_latitude": -90, + "west_longitude": -180, + "north_latitude": 90, + "east_longitude": 180 + }, + "id": { + "authority": "EPSG", + "code": 4326 + } +} + Testing projinfo -s EPSG:4326 -t EPSG:32631 Candidate operations found: 1 ------------------------------------- diff --git a/test/unit/test_datum.cpp b/test/unit/test_datum.cpp index 121b7c88ca..cf2e2f3a58 100644 --- a/test/unit/test_datum.cpp +++ b/test/unit/test_datum.cpp @@ -217,11 +217,7 @@ TEST(datum, prime_meridian_to_JSON) { " \"unit\": {\n" " \"type\": \"AngularUnit\",\n" " \"name\": \"degree\",\n" - " \"conversion_factor\": 0.0174532925199433,\n" - " \"id\": {\n" - " \"authority\": \"EPSG\",\n" - " \"code\": 9122\n" - " }\n" + " \"conversion_factor\": 0.0174532925199433\n" " }\n" " },\n" " \"id\": {\n" From 076e62a9357e819a0c13b3fb1915c29a2b3c98d5 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 6 Jul 2019 17:06:41 +0200 Subject: [PATCH 03/16] Add data/crsjson.schema.json --- data/Makefile.am | 4 +- data/crsjson.schema.json | 294 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 data/crsjson.schema.json diff --git a/data/Makefile.am b/data/Makefile.am index 1bf95cd2b9..096ba7c319 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -2,7 +2,8 @@ DATAPATH = $(top_srcdir)/data pkgdata_DATA = GL27 nad.lst nad27 nad83 world other.extra \ CH null \ - ITRF2000 ITRF2008 ITRF2014 proj.db + ITRF2000 ITRF2008 ITRF2014 proj.db \ + crsjson.schema.json SQL_ORDERED_LIST = sql/begin.sql \ sql/proj_db_table_defs.sql \ @@ -40,6 +41,7 @@ EXTRA_DIST = GL27 nad.lst nad27 nad83 \ world other.extra \ CH \ ITRF2000 ITRF2008 ITRF2014 \ + crsjson.schema.json \ CMakeLists.txt tests/test_nodata.gtx null \ generate_all_sql_in.cmake sql_filelist.cmake \ $(SQL_ORDERED_LIST) diff --git a/data/crsjson.schema.json b/data/crsjson.schema.json new file mode 100644 index 0000000000..5ceeaa1ed1 --- /dev/null +++ b/data/crsjson.schema.json @@ -0,0 +1,294 @@ +{ + "$id": "https://proj.org/crsjson.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Schema for CRS JSON", + + "oneOf": [ + { "$ref": "#/definitions/crs" }, + { "$ref": "#/definitions/datum" }, + { "$ref": "#/definitions/ellipsoid" }, + { "$ref": "#/definitions/prime_meridian" }, + { "$ref": "#/definitions/conversion" } + ], + + "definitions": { + + "axis": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["Axis"] }, + "name": { "type": "string" }, + "abbreviation": { "type": "string" }, + "direction": { "type": "string" }, + "unit": { "$ref": "#/definitions/unit" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name" ], + "additionalProperties": false + }, + + "bbox": { + "type": "object", + "properties": { + "east_longitude": { "type": "number" }, + "west_longitude": { "type": "number" }, + "south_latitude": { "type": "number" }, + "north_latitude": { "type": "number" } + }, + "required" : [ "east_longitude", "west_longitude", + "south_latitude", "north_latitude" ], + "additionalProperties": false + }, + + "conversion": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["Conversion"] }, + "name": { "type": "string" }, + "method": { "$ref": "#/definitions/method" }, + "parameters": { + "type": "array", + "items": { "$ref": "#/definitions/parameter_value" } + }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name", "method", "parameters" ], + "additionalProperties": false + }, + + "coordinate_system": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["CoordinateSystem"] }, + "name": { "type": "string" }, + "subtype": { "type": "string" }, + "axis": { + "type": "array", + "items": { "$ref": "#/definitions/axis" } + }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "subtype", "axis" ], + "additionalProperties": false + }, + + "crs": { + "oneOf": [ + { "$ref": "#/definitions/geodetic_crs" }, + { "$ref": "#/definitions/derived_crs" } + ] + }, + + "datum": { + "oneOf": [ { "$ref": "#/definitions/geodetic_reference_frame" } ] + }, + + "derived_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["ProjectedCRS", "DerivedGeodeticCRS", + "DerivedGeographicCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "ellipsoid": { + "type": "object", + "oneOf":[ + { + "properties": { + "type": { "type": "string", "enum": ["Ellipsoid"] }, + "name": { "type": "string" }, + "semi_major_axis": { "$ref": "#/definitions/value_and_unit" }, + "semi_minor_axis": { "$ref": "#/definitions/value_and_unit" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name", "semi_major_axis", "semi_minor_axis" ], + "additionalProperties": false + }, + { + "properties": { + "type": { "type": "string", "enum": ["Ellipsoid"] }, + "name": { "type": "string" }, + "semi_major_axis": { "$ref": "#/definitions/value_and_unit" }, + "inverse_flattening": { "type": "number" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name", "semi_major_axis", "inverse_flattening" ], + "additionalProperties": false + }, + { + "properties": { + "type": { "type": "string", "enum": ["Ellipsoid"] }, + "name": { "type": "string" }, + "radius": { "$ref": "#/definitions/value_and_unit" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name", "radius" ], + "additionalProperties": false + } + ] + }, + + "geodetic_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["GeodeticCRS", "GeographicCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/datum" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "geodetic_reference_frame": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["GeodeticReferenceFrame"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "ellipsoid": { "$ref": "#/definitions/ellipsoid" }, + "prime_meridian": { "$ref": "#/definitions/prime_meridian" }, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "ellipsoid" ], + "additionalProperties": false + }, + + "id": { + "type": "object", + "properties": { + "authority": { "type": "string" }, + "code": { + "oneOf": [ { "type": "string" }, { "type": "integer" } ] + } + }, + "required" : [ "authority", "code" ], + "additionalProperties": false + }, + + "method": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["OperationMethod"]}, + "name": { "type": "string" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name" ], + "additionalProperties": false + }, + + "object_usage": { + "anyOf": [ + { + "type": "object", + "properties": { + "area": { "type": "string" }, + "bbox": { "$ref": "#/definitions/bbox" }, + "remarks": { "type": "string" }, + "id": { "$ref": "#/definitions/id" } + } + }, + { + "type": "object", + "properties": { + "usages": { "$ref": "#/definitions/usages" }, + "remarks": { "type": "string" }, + "id": { "$ref": "#/definitions/id" } + } + } + ] + }, + + "parameter_value": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["ParameterValue"] }, + "name": { "type": "string" }, + "value": { + "oneOf": [ + { "type": "string" }, + { "type": "number" } + ] + }, + "unit": { "$ref": "#/definitions/unit" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name", "value" ], + "additionalProperties": false + }, + + "prime_meridian": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["PrimeMeridian"] }, + "name": { "type": "string" }, + "longitude": { "$ref": "#/definitions/value_and_unit" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name" ], + "additionalProperties": false + }, + + "unit": { + "type": "object", + "properties": { + "type": { "type": "string", + "enum": ["LinearUnit", "AngularUnit", "ScaleUnit", + "TimeUnit", "ParametricUnit", "Unit"] }, + "name": { "type": "string" }, + "conversion_factor": { "type": "number" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "type", "name" ], + "additionalProperties": false + }, + + "usages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "area": { "type": "string" }, + "bbox": { "$ref": "#/definitions/bbox" } + }, + "additionalProperties": false + } + }, + + "value_and_unit": { + "type": "object", + "properties": { + "value": { "type": "number" }, + "unit": { "$ref": "#/definitions/unit" } + }, + "required" : [ "value", "unit" ], + "additionalProperties": false + } + + } +} From d44e1e268c5da846455d3f73f94a283e80340b6c Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 6 Jul 2019 17:38:10 +0200 Subject: [PATCH 04/16] Travis: add testing of JSON output against schema and upgrade everything to Python3 --- travis/before_install.sh | 5 +++-- travis/csa/before_install.sh | 3 ++- travis/install.sh | 6 ++++++ travis/linux_clang/before_install.sh | 3 ++- travis/linux_gcc/before_install.sh | 7 ++++--- travis/linux_gcc7/before_install.sh | 2 ++ travis/mingw32/before_install.sh | 5 +++-- travis/osx/before_install.sh | 6 +++--- travis/osx/install.sh | 2 ++ 9 files changed, 27 insertions(+), 12 deletions(-) diff --git a/travis/before_install.sh b/travis/before_install.sh index 59b5be9ffb..a577a7ce73 100755 --- a/travis/before_install.sh +++ b/travis/before_install.sh @@ -4,5 +4,6 @@ # "global" before_install script. # Configure Python pip -pip install --user --upgrade pip -pip config --user set global.progress_bar off +pip3 install --user --upgrade pip +pip3 config --user set global.progress_bar off +pip3 install --user jsonschema diff --git a/travis/csa/before_install.sh b/travis/csa/before_install.sh index d93d8bec8f..58446f650c 100755 --- a/travis/csa/before_install.sh +++ b/travis/csa/before_install.sh @@ -1,10 +1,11 @@ #!/bin/bash set -e +sudo apt-get update -qq +sudo apt-get install -qq python3-pip ./travis/before_install.sh -sudo apt-get update -qq sudo apt-get install -qq sqlite3 libsqlite3-dev wget http://releases.llvm.org/6.0.0/clang+llvm-6.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz diff --git a/travis/install.sh b/travis/install.sh index d0bc37434c..bc6100da47 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -51,6 +51,12 @@ fi make check make install find /tmp/proj_autoconf_install_from_dist_all + +/tmp/proj_autoconf_install_from_dist_all/bin/projinfo EPSG:32631 -o JSON -q > out.json +cat out.json +echo "Validating JSON" +jsonschema -i out.json /tmp/proj_autoconf_install_from_dist_all/share/proj/crsjson.schema.json && echo "Valid !" + cd .. # cmake build from generated tarball diff --git a/travis/linux_clang/before_install.sh b/travis/linux_clang/before_install.sh index bd5447101f..167bc66749 100755 --- a/travis/linux_clang/before_install.sh +++ b/travis/linux_clang/before_install.sh @@ -1,8 +1,9 @@ #!/bin/bash set -e +sudo apt-get update -qq +sudo apt-get install -qq python3-pip ./travis/before_install.sh -sudo apt-get update -qq sudo apt-get install -qq sqlite3 libsqlite3-dev \ No newline at end of file diff --git a/travis/linux_gcc/before_install.sh b/travis/linux_gcc/before_install.sh index 4ac7c3b6e4..5564ff8ffc 100755 --- a/travis/linux_gcc/before_install.sh +++ b/travis/linux_gcc/before_install.sh @@ -1,10 +1,11 @@ #!/bin/bash set -e +sudo apt-get update -qq +sudo apt-get install -qq python3-pip ./travis/before_install.sh -sudo apt-get update -qq sudo apt-get install -y cppcheck sudo apt-get install -qq lcov sudo apt-get install -qq doxygen graphviz @@ -14,7 +15,7 @@ sudo apt-get install -qq openjdk-7-jdk scripts/cppcheck.sh scripts/doxygen.sh -pip install --user sphinxcontrib-bibtex -pip install --user cpp-coveralls +pip3 install --user sphinxcontrib-bibtex +pip3 install --user cpp-coveralls ./travis/docker.sh diff --git a/travis/linux_gcc7/before_install.sh b/travis/linux_gcc7/before_install.sh index 25c7483f3b..50fd4c3635 100755 --- a/travis/linux_gcc7/before_install.sh +++ b/travis/linux_gcc7/before_install.sh @@ -1,6 +1,8 @@ #!/bin/bash set -e +sudo apt-get update -qq +sudo apt-get install -qq python3-pip ./travis/before_install.sh diff --git a/travis/mingw32/before_install.sh b/travis/mingw32/before_install.sh index d2bbe3ec7d..d67d819491 100755 --- a/travis/mingw32/before_install.sh +++ b/travis/mingw32/before_install.sh @@ -1,10 +1,11 @@ #!/bin/bash set -e +sudo apt-get update -qq +sudo apt-get install -qq python3-pip ./travis/before_install.sh -sudo apt-get update -qq sudo apt-get install wget sudo apt-get install binutils-mingw-w64-x86-64 sudo apt-get install gcc-mingw-w64-x86-64 @@ -12,4 +13,4 @@ sudo apt-get install g++-mingw-w64-x86-64 sudo apt-get install g++-mingw-w64 sudo apt-get install mingw-w64-tools sudo apt-get install -y wine1.4-amd64 -sudo apt-get install sqlite3 \ No newline at end of file +sudo apt-get install sqlite3 diff --git a/travis/osx/before_install.sh b/travis/osx/before_install.sh index 964fbc67bc..55c0667a3a 100755 --- a/travis/osx/before_install.sh +++ b/travis/osx/before_install.sh @@ -2,6 +2,8 @@ set -e +export PATH=$HOME/Library/Python/3.6/bin:$PATH + ./travis/before_install.sh brew update @@ -10,8 +12,6 @@ brew install sqlite3 brew install doxygen brew install md5sha1sum -export PATH=$HOME/Library/Python/2.7/bin:$PATH -# breathe=4.12.0 is the last version to work for us with sphinx 1.8.5 / Python 2 -pip install --user sphinx sphinx-rtd-theme sphinxcontrib-bibtex breathe==4.12.0 +pip3 install --user sphinx sphinx-rtd-theme sphinxcontrib-bibtex breathe which sphinx-build (cd docs; make html) diff --git a/travis/osx/install.sh b/travis/osx/install.sh index 4869ee657f..ff5266f668 100755 --- a/travis/osx/install.sh +++ b/travis/osx/install.sh @@ -5,4 +5,6 @@ set -e export CCACHE_CPP2=yes export PROJ_DB_CACHE_DIR="$HOME/.ccache" +export PATH=$HOME/Library/Python/3.6/bin:$PATH + CC="ccache clang" CXX="ccache clang++" CFLAGS="-Werror -O2" CXXFLAGS="-Werror -O2" ./travis/install.sh From ec49c9cd0aa9de24623920b8de226daf05a0e90f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 8 Aug 2019 19:18:26 +0200 Subject: [PATCH 05/16] projinfo: rename JSON to PROJJSON --- src/apps/projinfo.cpp | 22 +++++++++++----------- test/cli/testprojinfo_out.dist | 2 +- travis/install.sh | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 6b1267e00e..6cacdd660c 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -67,7 +67,7 @@ struct OutputOptions { bool WKT2_2015_SIMPLIFIED = false; bool WKT1_GDAL = false; bool WKT1_ESRI = false; - bool JSON = false; + bool PROJJSON = false; bool c_ify = false; bool singleLine = false; bool strict = true; @@ -102,7 +102,7 @@ static void usage() { std::cerr << std::endl; std::cerr << "-o: formats is a comma separated combination of: " "all,default,PROJ,WKT_ALL,WKT2_2015,WKT2_2018,WKT1_GDAL," - "WKT1_ESRI,JSON" + "WKT1_ESRI,PROJJSON" << std::endl; std::cerr << " Except 'all' and 'default', other format can be preceded " "by '-' to disable them" @@ -474,20 +474,20 @@ static void outputObject( auto JSONExportable = nn_dynamic_pointer_cast(obj); if (JSONExportable) { - if (outputOpt.JSON) { + if (outputOpt.PROJJSON) { try { if (alreadyOutputed) { std::cout << std::endl; } if (!outputOpt.quiet) { - std::cout << "JSON:" << std::endl; + std::cout << "PROJJSON:" << std::endl; } std::cout << JSONExportable->exportToJSON( JSONFormatter::create(dbContext).get()) << std::endl; } catch (const std::exception &e) { - std::cerr << "Error when exporting to JSON: " << e.what() + std::cerr << "Error when exporting to PROJJSON: " << e.what() << std::endl; } // alreadyOutputed = true; @@ -744,7 +744,7 @@ int main(int argc, char **argv) { outputOpt.WKT2_2015 = true; outputOpt.WKT1_GDAL = true; outputOpt.WKT1_ESRI = true; - outputOpt.JSON = true; + outputOpt.PROJJSON = true; } else if (ci_equal(format, "default")) { outputOpt.PROJ5 = true; outputOpt.WKT2_2018 = true; @@ -804,10 +804,10 @@ int main(int argc, char **argv) { ci_equal(format, "-WKT1-ESRI") || ci_equal(format, "-WKT1:ESRI")) { outputOpt.WKT1_ESRI = false; - } else if (ci_equal(format, "JSON")) { - outputOpt.JSON = true; - } else if (ci_equal(format, "-JSON")) { - outputOpt.JSON = false; + } else if (ci_equal(format, "PROJJSON")) { + outputOpt.PROJJSON = true; + } else if (ci_equal(format, "-PROJJSON")) { + outputOpt.PROJJSON = false; } else { std::cerr << "Unrecognized value for option -o: " << format << std::endl; @@ -1027,7 +1027,7 @@ int main(int argc, char **argv) { if (outputOpt.quiet && (outputOpt.PROJ5 + outputOpt.WKT2_2018 + outputOpt.WKT2_2015 + - outputOpt.WKT1_GDAL + outputOpt.JSON) != 1) { + outputOpt.WKT1_GDAL + outputOpt.PROJJSON) != 1) { std::cerr << "-q can only be used with a single output format" << std::endl; usage(); diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index 20ae544aeb..530a0426db 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -135,7 +135,7 @@ WKT1_ESRI: GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] -JSON: +PROJJSON: { "type": "GeographicCRS", "name": "WGS 84", diff --git a/travis/install.sh b/travis/install.sh index bc6100da47..7a31e5c26a 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -52,7 +52,7 @@ make check make install find /tmp/proj_autoconf_install_from_dist_all -/tmp/proj_autoconf_install_from_dist_all/bin/projinfo EPSG:32631 -o JSON -q > out.json +/tmp/proj_autoconf_install_from_dist_all/bin/projinfo EPSG:32631 -o PROJJSON -q > out.json cat out.json echo "Validating JSON" jsonschema -i out.json /tmp/proj_autoconf_install_from_dist_all/share/proj/crsjson.schema.json && echo "Valid !" From 89f2cc7ec4178a369e73e9cd115a2552a55d870a Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 8 Aug 2019 20:04:20 +0200 Subject: [PATCH 06/16] PROJJSON export: use more compact form --- data/crsjson.schema.json | 45 ++++++++++++++++++---------- include/proj/io.hpp | 2 ++ src/iso19111/coordinateoperation.cpp | 11 ++++++- src/iso19111/coordinatesystem.cpp | 9 +++++- src/iso19111/crs.cpp | 7 +++++ src/iso19111/datum.cpp | 30 +++++++++++++------ src/iso19111/io.cpp | 10 ++++++- test/cli/testprojinfo_out.dist | 37 ++--------------------- test/unit/test_datum.cpp | 27 ++++++++++++----- 9 files changed, 109 insertions(+), 69 deletions(-) diff --git a/data/crsjson.schema.json b/data/crsjson.schema.json index 5ceeaa1ed1..86f1e13ef0 100644 --- a/data/crsjson.schema.json +++ b/data/crsjson.schema.json @@ -111,8 +111,8 @@ "properties": { "type": { "type": "string", "enum": ["Ellipsoid"] }, "name": { "type": "string" }, - "semi_major_axis": { "$ref": "#/definitions/value_and_unit" }, - "semi_minor_axis": { "$ref": "#/definitions/value_and_unit" }, + "semi_major_axis": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, + "semi_minor_axis": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, "id": { "$ref": "#/definitions/id" } }, "required" : [ "name", "semi_major_axis", "semi_minor_axis" ], @@ -122,7 +122,7 @@ "properties": { "type": { "type": "string", "enum": ["Ellipsoid"] }, "name": { "type": "string" }, - "semi_major_axis": { "$ref": "#/definitions/value_and_unit" }, + "semi_major_axis": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, "inverse_flattening": { "type": "number" }, "id": { "$ref": "#/definitions/id" } }, @@ -133,7 +133,7 @@ "properties": { "type": { "type": "string", "enum": ["Ellipsoid"] }, "name": { "type": "string" }, - "radius": { "$ref": "#/definitions/value_and_unit" }, + "radius": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, "id": { "$ref": "#/definitions/id" } }, "required" : [ "name", "radius" ], @@ -255,17 +255,25 @@ }, "unit": { - "type": "object", - "properties": { - "type": { "type": "string", - "enum": ["LinearUnit", "AngularUnit", "ScaleUnit", - "TimeUnit", "ParametricUnit", "Unit"] }, - "name": { "type": "string" }, - "conversion_factor": { "type": "number" }, - "id": { "$ref": "#/definitions/id" } - }, - "required" : [ "type", "name" ], - "additionalProperties": false + "oneOf": [ + { + "type": "string", + "enum": ["metre", "degree", "unity"] + }, + { + "type": "object", + "properties": { + "type": { "type": "string", + "enum": ["LinearUnit", "AngularUnit", "ScaleUnit", + "TimeUnit", "ParametricUnit", "Unit"] }, + "name": { "type": "string" }, + "conversion_factor": { "type": "number" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "type", "name" ], + "additionalProperties": false + } + ] }, "usages": { @@ -288,6 +296,13 @@ }, "required" : [ "value", "unit" ], "additionalProperties": false + }, + + "value_in_metre_or_value_and_unit": { + "oneOf": [ + { "type": "number" }, + { "$ref": "#/definitions/value_and_unit" } + ] } } diff --git a/include/proj/io.hpp b/include/proj/io.hpp index cfb4b3f783..043b4c4be6 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -503,6 +503,8 @@ class PROJ_GCC_DLL JSONFormatter { PROJ_INTERNAL void setAllowIDInImmediateChild(); + PROJ_INTERNAL void setOmitTypeInImmediateChild(); + // cppcheck-suppress functionStatic PROJ_INTERNAL bool outputId() const; diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index a2a31edd93..f4e90fe806 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -1200,7 +1200,14 @@ void OperationParameterValue::_exportToJSON( writer.AddObjKey("value"); writer.Add(l_value->value().value(), 15); writer.AddObjKey("unit"); - l_value->value().unit()._exportToJSON(formatter); + const auto &l_unit(l_value->value().unit()); + if (l_unit == common::UnitOfMeasure::METRE || + l_unit == common::UnitOfMeasure::DEGREE || + l_unit == common::UnitOfMeasure::SCALE_UNITY) { + writer.Add(l_unit.name()); + } else { + l_unit._exportToJSON(formatter); + } } else if (l_value->type() == ParameterValue::Type::FILENAME) { writer.AddObjKey("value"); writer.Add(l_value->valueFile()); @@ -5473,6 +5480,7 @@ void Conversion::_exportToJSON( } writer.AddObjKey("method"); + formatter->setOmitTypeInImmediateChild(); formatter->setAllowIDInImmediateChild(); method()->_exportToJSON(formatter); @@ -5481,6 +5489,7 @@ void Conversion::_exportToJSON( auto parametersContext(writer.MakeArrayContext(false)); for (const auto &genOpParamvalue : parameterValues()) { formatter->setAllowIDInImmediateChild(); + formatter->setOmitTypeInImmediateChild(); genOpParamvalue->_exportToJSON(formatter); } } diff --git a/src/iso19111/coordinatesystem.cpp b/src/iso19111/coordinatesystem.cpp index f96a962fb5..ef53dd5743 100644 --- a/src/iso19111/coordinatesystem.cpp +++ b/src/iso19111/coordinatesystem.cpp @@ -410,7 +410,13 @@ void CoordinateSystemAxis::_exportToJSON( writer.Add(direction().toString()); writer.AddObjKey("unit"); - unit()._exportToJSON(formatter); + const auto &l_unit(unit()); + if (l_unit == common::UnitOfMeasure::METRE || + l_unit == common::UnitOfMeasure::DEGREE) { + writer.Add(l_unit.name()); + } else { + l_unit._exportToJSON(formatter); + } if (formatter->outputId()) { formatID(formatter); @@ -577,6 +583,7 @@ void CoordinateSystem::_exportToJSON( auto axisContext(writer.MakeArrayContext(false)); const auto &l_axisList = axisList(); for (auto &axis : l_axisList) { + formatter->setOmitTypeInImmediateChild(); axis->_exportToJSON(formatter); } diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 2ca2786d1f..670d0c1a77 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -1366,6 +1366,7 @@ void GeodeticCRS::_exportToJSON( } writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); coordinateSystem()->_exportToJSON(formatter); ObjectUsage::baseExportToJSON(formatter); @@ -2116,6 +2117,7 @@ void GeographicCRS::_exportToJSON( } writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); coordinateSystem()->_exportToJSON(formatter); ObjectUsage::baseExportToJSON(formatter); @@ -2940,12 +2942,15 @@ void ProjectedCRS::_exportToJSON( writer.AddObjKey("base_crs"); formatter->setAllowIDInImmediateChild(); + formatter->setOmitTypeInImmediateChild(); baseCRS()->_exportToJSON(formatter); writer.AddObjKey("conversion"); + formatter->setOmitTypeInImmediateChild(); derivingConversionRef()->_exportToJSON(formatter); writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); coordinateSystem()->_exportToJSON(formatter); ObjectUsage::baseExportToJSON(formatter); @@ -4316,6 +4321,7 @@ void DerivedGeodeticCRS::_exportToJSON( derivingConversionRef()->_exportToJSON(formatter); writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); coordinateSystem()->_exportToJSON(formatter); ObjectUsage::baseExportToJSON(formatter); @@ -4485,6 +4491,7 @@ void DerivedGeographicCRS::_exportToJSON( derivingConversionRef()->_exportToJSON(formatter); writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); coordinateSystem()->_exportToJSON(formatter); ObjectUsage::baseExportToJSON(formatter); diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 89ecc7556d..2944da1eb6 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -376,12 +376,13 @@ void PrimeMeridian::_exportToJSON( const auto &l_long = longitude(); writer.AddObjKey("longitude"); - { + const auto &unit = l_long.unit(); + if (unit == common::UnitOfMeasure::DEGREE) { + writer.Add(l_long.value(), 15); + } else { auto longitudeContext(formatter->MakeObjectContext(nullptr, false)); writer.AddObjKey("value"); writer.Add(l_long.value(), 15); - - const auto &unit = l_long.unit(); writer.AddObjKey("unit"); unit._exportToJSON(formatter); } @@ -834,7 +835,9 @@ void Ellipsoid::_exportToJSON( const auto &semiMajor = semiMajorAxis(); const auto &semiMajorUnit = semiMajor.unit(); writer.AddObjKey(isSphere() ? "radius" : "semi_major_axis"); - { + if (semiMajorUnit == common::UnitOfMeasure::METRE) { + writer.Add(semiMajor.value(), 15); + } else { auto objContext(formatter->MakeObjectContext(nullptr, false)); writer.AddObjKey("value"); writer.Add(semiMajor.value(), 15); @@ -850,13 +853,17 @@ void Ellipsoid::_exportToJSON( writer.Add(l_inverseFlattening->getSIValue(), 15); } else { writer.AddObjKey("semi_minor_axis"); - { + const auto &l_semiMinorAxis(semiMinorAxis()); + const auto &semiMinorAxisUnit(l_semiMinorAxis->unit()); + if (semiMinorAxisUnit == common::UnitOfMeasure::METRE) { + writer.Add(l_semiMinorAxis->value(), 15); + } else { auto objContext(formatter->MakeObjectContext(nullptr, false)); writer.AddObjKey("value"); - writer.Add(semiMinorAxis()->value(), 15); + writer.Add(l_semiMinorAxis->value(), 15); writer.AddObjKey("unit"); - semiMinorAxis()->unit()._exportToJSON(formatter); + semiMinorAxisUnit._exportToJSON(formatter); } } } @@ -1272,10 +1279,15 @@ void GeodeticReferenceFrame::_exportToJSON( Datum::getPrivate()->exportAnchorDefinition(formatter); writer.AddObjKey("ellipsoid"); + formatter->setOmitTypeInImmediateChild(); ellipsoid()->_exportToJSON(formatter); - writer.AddObjKey("prime_meridian"); - primeMeridian()->_exportToJSON(formatter); + const auto &l_primeMeridian(primeMeridian()); + if (l_primeMeridian->nameStr() != "Greenwich") { + writer.AddObjKey("prime_meridian"); + formatter->setOmitTypeInImmediateChild(); + primeMeridian()->_exportToJSON(formatter); + } ObjectUsage::baseExportToJSON(formatter); } diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 35798d9d77..bb15c80aa5 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -8027,6 +8027,7 @@ struct JSONFormatter::Private { std::vector stackHasId_{false}; std::vector outputIdStack_{true}; bool allowIDInImmediateChild_ = false; + bool omitTypeInImmediateChild_ = false; std::string result_{}; @@ -8102,14 +8103,21 @@ void JSONFormatter::setAllowIDInImmediateChild() { // --------------------------------------------------------------------------- +void JSONFormatter::setOmitTypeInImmediateChild() { + d->omitTypeInImmediateChild_ = true; +} + +// --------------------------------------------------------------------------- + JSONFormatter::ObjectContext::ObjectContext(JSONFormatter &formatter, const char *objectType, bool hasId) : m_formatter(formatter) { m_formatter.d->writer_.StartObj(); - if (objectType) { + if (objectType && !m_formatter.d->omitTypeInImmediateChild_) { m_formatter.d->writer_.AddObjKey("type"); m_formatter.d->writer_.Add(objectType); } + m_formatter.d->omitTypeInImmediateChild_ = false; // All intermediate nodes shouldn't have ID if a parent has an ID // unless explicitly enabled. if (m_formatter.d->allowIDInImmediateChild_) { diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index 530a0426db..73751b9968 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -143,56 +143,25 @@ PROJJSON: "type": "GeodeticReferenceFrame", "name": "World Geodetic System 1984", "ellipsoid": { - "type": "Ellipsoid", "name": "WGS 84", - "semi_major_axis": { - "value": 6378137, - "unit": { - "type": "LinearUnit", - "name": "metre", - "conversion_factor": 1 - } - }, + "semi_major_axis": 6378137, "inverse_flattening": 298.257223563 - }, - "prime_meridian": { - "type": "PrimeMeridian", - "name": "Greenwich", - "longitude": { - "value": 0, - "unit": { - "type": "AngularUnit", - "name": "degree", - "conversion_factor": 0.0174532925199433 - } - } } }, "coordinate_system": { - "type": "CoordinateSystem", "subtype": "ellipsoidal", "axis": [ { - "type": "Axis", "name": "Geodetic latitude", "abbreviation": "Lat", "direction": "north", - "unit": { - "type": "AngularUnit", - "name": "degree", - "conversion_factor": 0.0174532925199433 - } + "unit": "degree" }, { - "type": "Axis", "name": "Geodetic longitude", "abbreviation": "Lon", "direction": "east", - "unit": { - "type": "AngularUnit", - "name": "degree", - "conversion_factor": 0.0174532925199433 - } + "unit": "degree" } ] }, diff --git a/test/unit/test_datum.cpp b/test/unit/test_datum.cpp index cf2e2f3a58..d8fab1f067 100644 --- a/test/unit/test_datum.cpp +++ b/test/unit/test_datum.cpp @@ -212,19 +212,30 @@ TEST(datum, prime_meridian_to_JSON) { "{\n" " \"type\": \"PrimeMeridian\",\n" " \"name\": \"Greenwich\",\n" - " \"longitude\": {\n" - " \"value\": 0,\n" - " \"unit\": {\n" - " \"type\": \"AngularUnit\",\n" - " \"name\": \"degree\",\n" - " \"conversion_factor\": 0.0174532925199433\n" - " }\n" - " },\n" + " \"longitude\": 0,\n" " \"id\": {\n" " \"authority\": \"EPSG\",\n" " \"code\": 8901\n" " }\n" "}"); + + EXPECT_EQ(PrimeMeridian::PARIS->exportToJSON(JSONFormatter::create().get()), + "{\n" + " \"type\": \"PrimeMeridian\",\n" + " \"name\": \"Paris\",\n" + " \"longitude\": {\n" + " \"value\": 2.5969213,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"grad\",\n" + " \"conversion_factor\": 0.015707963267949\n" + " }\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8903\n" + " }\n" + "}"); } // --------------------------------------------------------------------------- From 81bd57dfd8cfae609288643d1b09a4805f1bcded Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 9 Aug 2019 12:59:49 +0200 Subject: [PATCH 07/16] createFromUserInput(): add capability to import PROJJSON --- configure.ac | 4 +- include/proj/internal/Makefile.am | 5 +- .../proj/internal/include_nlohmann_json.hpp | 10 + include/proj/internal/nlohmann/Makefile.am | 2 + include/proj/internal/nlohmann/json.hpp | 22684 ++++++++++++++++ scripts/cppcheck.sh | 2 +- src/apps/projinfo.cpp | 10 +- src/iso19111/io.cpp | 577 + test/unit/test_io.cpp | 480 + 9 files changed, 23765 insertions(+), 9 deletions(-) create mode 100644 include/proj/internal/include_nlohmann_json.hpp create mode 100644 include/proj/internal/nlohmann/Makefile.am create mode 100644 include/proj/internal/nlohmann/json.hpp diff --git a/configure.ac b/configure.ac index 3955829867..dc09054e19 100644 --- a/configure.ac +++ b/configure.ac @@ -131,9 +131,6 @@ AX_CHECK_COMPILE_FLAG([-Wdeprecated], [CXX_WFLAGS="$CXX_WFLAGS -Wdeprecated"],,[ AX_CHECK_COMPILE_FLAG([-Wabstract-vbase-init], [CXX_WFLAGS="$CXX_WFLAGS -Wabstract-vbase-init"],,[$ERROR_ON_UNKNOWN_OPTIONS]) AX_CHECK_COMPILE_FLAG([-Winconsistent-missing-destructor-override], [CXX_WFLAGS="$CXX_WFLAGS -Winconsistent-missing-destructor-override"],,[$ERROR_ON_UNKNOWN_OPTIONS]) -dnl Forbid use of 'or', 'and', ... alias operators -AX_CHECK_COMPILE_FLAG([-fno-operator-names], [CXX_WFLAGS="$CXX_WFLAGS -fno-operator-names"],,[$ERROR_ON_UNKNOWN_OPTIONS]) - HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT=no AX_CHECK_COMPILE_FLAG([-Wzero-as-null-pointer-constant], [CXX_WFLAGS="$CXX_WFLAGS -Wzero-as-null-pointer-constant" HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT=yes NO_ZERO_AS_NULL_POINTER_CONSTANT_FLAG="-Wno-zero-as-null-pointer-constant"],,[$ERROR_ON_UNKNOWN_OPTIONS]) if test "$HAVE_GCC_WARNING_ZERO_AS_NULL_POINTER_CONSTANT" = "yes"; then @@ -344,6 +341,7 @@ dnl Generate files dnl --------------------------------------------------------------------------- AC_CONFIG_FILES([Makefile cmake/Makefile src/Makefile include/Makefile include/proj/Makefile include/proj/internal/Makefile + include/proj/internal/nlohmann/Makefile test/Makefile test/cli/Makefile test/gie/Makefile test/gigs/Makefile test/unit/Makefile man/Makefile man/man1/Makefile man/man3/Makefile data/Makefile jniwrap/Makefile jniwrap/org.osgeo.proj/Makefile jniwrap/org.osgeo.proj/org/Makefile jniwrap/org.osgeo.proj/org/proj4/Makefile]) diff --git a/include/proj/internal/Makefile.am b/include/proj/internal/Makefile.am index ddd2686c42..f5bbeb7bed 100644 --- a/include/proj/internal/Makefile.am +++ b/include/proj/internal/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = nlohmann + noinst_HEADERS = \ coordinateoperation_constants.hpp \ coordinateoperation_internal.hpp \ @@ -5,4 +7,5 @@ noinst_HEADERS = \ coordinatesystem_internal.hpp \ internal.hpp \ io_internal.hpp \ - lru_cache.hpp + lru_cache.hpp \ + include_nlohmann_json.hpp diff --git a/include/proj/internal/include_nlohmann_json.hpp b/include/proj/internal/include_nlohmann_json.hpp new file mode 100644 index 0000000000..7f7b8fa9c1 --- /dev/null +++ b/include/proj/internal/include_nlohmann_json.hpp @@ -0,0 +1,10 @@ +#if defined(__GNUC__) +#pragma GCC system_header +#endif + +// to avoid any clash if PROJ users have another version of nlohmann/json.hpp +#define nlohmann proj_nlohmann + +#if !defined(DOXYGEN_ENABLED) +#include "nlohmann/json.hpp" +#endif diff --git a/include/proj/internal/nlohmann/Makefile.am b/include/proj/internal/nlohmann/Makefile.am new file mode 100644 index 0000000000..eaf3200e38 --- /dev/null +++ b/include/proj/internal/nlohmann/Makefile.am @@ -0,0 +1,2 @@ +noinst_HEADERS = \ + json.hpp diff --git a/include/proj/internal/nlohmann/json.hpp b/include/proj/internal/nlohmann/json.hpp new file mode 100644 index 0000000000..2a32a82963 --- /dev/null +++ b/include/proj/internal/nlohmann/json.hpp @@ -0,0 +1,22684 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.7.0 +|_____|_____|_____|_|___| 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 0 + +#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 < 9) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 9 + +#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) + #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_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(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_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) [[deprecated("Since " #since)]] + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) [[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 [[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 [[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_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_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("-Wvariadic-macros") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(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 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_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_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__)) +#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 \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + !defined(JSON_HEDLEY_PGI_VERSION) + #if \ + (__cplusplus >= 201703L) || \ + ((__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)) + #define JSON_HEDLEY_FALL_THROUGH [[fallthrough]] + #elif (__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough) + #define JSON_HEDLEY_FALL_THROUGH [[clang::fallthrough]] + #elif (__cplusplus >= 201103L) && JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) + #define JSON_HEDLEY_FALL_THROUGH [[gnu::fallthrough]] + #endif +#endif +#if !defined(JSON_HEDLEY_FALL_THROUGH) + #if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) + #elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough + #else + #define JSON_HEDLEY_FALL_THROUGH + #endif +#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 +/* Note the double-underscore. For internal use only; no API + * guarantees! */ +#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) || \ + 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 >= 201703L)) || \ + 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) static_assert(expr, message) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr) +#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_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_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_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_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE_MSG(expr, msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#define JSON_HEDLEY_REQUIRE(expr) JSON_HEDLEY_REQUIRE_MSG(expr, #expr) + +#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 + +/* 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