diff --git a/include/SimpleJson/DefaultTypes.hpp b/include/SimpleJson/DefaultTypes.hpp index da3e898..4db3492 100644 --- a/include/SimpleJson/DefaultTypes.hpp +++ b/include/SimpleJson/DefaultTypes.hpp @@ -106,6 +106,10 @@ template using JsonWriterDictT = JsonWriterDictImpl<_KeyWriter, _ValWriter, ToStringType, IMContainerType>; +template +using JsonWriterOrdDictT = + JsonWriterOrdDictImpl<_KeyWriter, _ValWriter, ToStringType>; + template using JsonWriterStaticDictT = JsonWriterStaticDictImpl<_KeyWriter, _ValWriter, ToStringType, IMContainerType>; diff --git a/include/SimpleJson/DictWriter.hpp b/include/SimpleJson/DictWriter.hpp index 56d4c16..bf8f12f 100644 --- a/include/SimpleJson/DictWriter.hpp +++ b/include/SimpleJson/DictWriter.hpp @@ -5,6 +5,10 @@ #pragma once +#include +#include +#include + #include "Internal/SimpleObjects.hpp" #include "Utils.hpp" @@ -88,6 +92,89 @@ struct JsonWriterDictBase }; // struct JsonWriterDictBase +template< + typename _KeyWriter, + typename _ObjWriter, + typename _ToStringType, + typename _DictTraits> +struct JsonWriterDynOrderedDictBase +{ + + template + inline static void Write(_OutputIt destIt, + const typename _DictTraits::DictBase& obj, + const WriterConfig& config, + const WriterStates& state) + { + using _KeyType = typename _DictTraits::key_type; + std::vector > keys; + + // Get all keys and sort them + keys.reserve(obj.size()); + for(auto it = obj.cbegin(); it != obj.cend(); ++it) + { + keys.emplace_back(_DictTraits::GetKey(*it)); + } + std::sort(keys.begin(), keys.end(), std::less<_KeyType>()); + + // Write the dict by the sorted keys + *destIt++ = '{'; + + WriterStates stateNextLevel = state; + ++(stateNextLevel.m_nestLevel); + size_t len = obj.size(); + + if (config.m_indent.size() > 0 && obj.size() > 0) + { + Internal::RepeatOutput(destIt, config.m_lineEnd, 1); + } + + for(auto it = keys.cbegin(); it != keys.cend(); ++it, --len) + { + const auto& key = it->get(); + + if (config.m_indent.size() > 0) + { + Internal::RepeatOutput(destIt, + config.m_indent, stateNextLevel.m_nestLevel); + } + + _KeyWriter::Write(destIt, key, config, stateNextLevel); + + if (config.m_indent.size() > 0) + { + *destIt++ = ' '; + *destIt++ = ':'; + *destIt++ = ' '; + } + else + { + *destIt++ = ':'; + } + + const auto& val = obj[key]; + _ObjWriter::Write(destIt, val, config, stateNextLevel); + + if (len != 1) + { + *destIt++ = ','; + } + + if (config.m_indent.size() > 0) + { + Internal::RepeatOutput(destIt, config.m_lineEnd, 1); + } + } + + if (config.m_indent.size() > 0 && obj.size() > 0) + { + Internal::RepeatOutput(destIt, config.m_indent, state.m_nestLevel); + } + *destIt++ = '}'; + } + +}; // struct JsonWriterDynOrderedDictBase + template struct DynamicDictTraits { @@ -156,6 +243,19 @@ struct JsonWriterDictImpl : { }; // struct JsonWriterDictImpl +template< + typename _KeyWriter, + typename _ObjWriter, + typename _ToStringType> +struct JsonWriterOrdDictImpl : + public JsonWriterDynOrderedDictBase< + _KeyWriter, + _ObjWriter, + _ToStringType, + DynamicDictTraits<_ToStringType> > +{ +}; // struct JsonWriterOrdDictImpl + template< typename _KeyWriter, typename _ObjWriter, @@ -169,6 +269,6 @@ struct JsonWriterStaticDictImpl : _ContainerType, StaticDictTraits<_ToStringType> > { -}; // struct JsonWriterDictImpl +}; // struct JsonWriterStaticDictImpl } // namespace SimpleJson diff --git a/include/SimpleJson/Internal/NumberParser.hpp b/include/SimpleJson/Internal/NumberParser.hpp index e83f0bc..80ce685 100644 --- a/include/SimpleJson/Internal/NumberParser.hpp +++ b/include/SimpleJson/Internal/NumberParser.hpp @@ -249,7 +249,7 @@ namespace SIMPLEJSON_CUSTOMIZED_NAMESPACE inline _LowType StdNumberDownCast(const _HighType& highVal) { if (std::numeric_limits<_LowType>::lowest() <= highVal && - highVal <= std::numeric_limits<_LowType>::max()) + highVal <= (std::numeric_limits<_LowType>::max)()) { return static_cast<_LowType>(highVal); } diff --git a/include/SimpleJson/ObjectWriter.hpp b/include/SimpleJson/ObjectWriter.hpp index dd531da..8e05533 100644 --- a/include/SimpleJson/ObjectWriter.hpp +++ b/include/SimpleJson/ObjectWriter.hpp @@ -87,6 +87,8 @@ struct JsonWriterObjectImpl using KeyWriter = _KeyWriter; using DictWriter = JsonWriterDictImpl; + using OrdDictWriter = + JsonWriterOrdDictImpl; using StaticDictWriter = JsonWriterStaticDictImpl; @@ -113,7 +115,14 @@ struct JsonWriterObjectImpl ListWriter::Write(destIt, obj.AsList(), config, state); break; case Internal::Obj::ObjCategory::Dict: - DictWriter::Write(destIt, obj.AsDict(), config, state); + if (config.m_orderDict) + { + OrdDictWriter::Write(destIt, obj.AsDict(), config, state); + } + else + { + DictWriter::Write(destIt, obj.AsDict(), config, state); + } break; case Internal::Obj::ObjCategory::StaticDict: StaticDictWriter::Write(destIt, obj.AsStaticDict(), config, state); diff --git a/include/SimpleJson/SimpleJson.hpp b/include/SimpleJson/SimpleJson.hpp index b716363..fc16c1c 100644 --- a/include/SimpleJson/SimpleJson.hpp +++ b/include/SimpleJson/SimpleJson.hpp @@ -3,6 +3,10 @@ // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT. + +#pragma once + + #include "DefaultTypes.hpp" #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE @@ -27,11 +31,21 @@ struct FindObjWriter using type = JsonWriterObject; }; // struct FindObjWriter +template<> +struct FindObjWriter : + public FindObjWriter +{}; // struct FindObjWriter + template<> struct FindObjWriter : public FindObjWriter {}; // struct FindObjWriter +template<> +struct FindObjWriter : + public FindObjWriter +{}; // struct FindObjWriter + template<> struct FindObjWriter { diff --git a/include/SimpleJson/WriterConfig.hpp b/include/SimpleJson/WriterConfig.hpp index 4ea6474..d9eec4c 100644 --- a/include/SimpleJson/WriterConfig.hpp +++ b/include/SimpleJson/WriterConfig.hpp @@ -19,13 +19,15 @@ struct WriterConfig { WriterConfig() : m_indent(""), - m_lineEnd("\n") + m_lineEnd("\n"), + m_orderDict(false) {} ~WriterConfig() = default; std::string m_indent; std::string m_lineEnd; + bool m_orderDict; }; // struct WriterConfig diff --git a/test/src/TestBoolParser.cpp b/test/src/TestBoolParser.cpp index 28a7b08..88c1ac3 100644 --- a/test/src/TestBoolParser.cpp +++ b/test/src/TestBoolParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestDictParser.cpp b/test/src/TestDictParser.cpp index 527c355..e3e9736 100644 --- a/test/src/TestDictParser.cpp +++ b/test/src/TestDictParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestGenericParser.cpp b/test/src/TestGenericParser.cpp index 7152df4..655f4e7 100644 --- a/test/src/TestGenericParser.cpp +++ b/test/src/TestGenericParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestInputStateMachine.cpp b/test/src/TestInputStateMachine.cpp index 1b43938..8ba5e03 100644 --- a/test/src/TestInputStateMachine.cpp +++ b/test/src/TestInputStateMachine.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #include diff --git a/test/src/TestJsonWriter.cpp b/test/src/TestJsonWriter.cpp index 12bd03d..53cc030 100644 --- a/test/src/TestJsonWriter.cpp +++ b/test/src/TestJsonWriter.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE @@ -362,3 +365,69 @@ GTEST_TEST(TestJsonWriter, ObjectWriter) EXPECT_EQ(res, "{\"string\":\"string\"}"); } } + +GTEST_TEST(TestJsonWriter, OrderedDictWriter) +{ + using _Str = Internal::Obj::String; + using _Dict = Internal::Obj::Dict; + + WriterConfig config; + config.m_orderDict = true; + + { + std::string expOut = + "{\"0\":0,\"1\":1,\"2\":2,\"a\":\"a\",\"b\":\"b\",\"c\":\"c\"}"; + _Dict dict; + dict[_Str("a")] = _Str("a"); + dict[_Str("b")] = _Str("b"); + dict[_Str("c")] = _Str("c"); + dict[_Str("0")] = Internal::Obj::Int64(0); + dict[_Str("1")] = Internal::Obj::Int64(1); + dict[_Str("2")] = Internal::Obj::Int64(2); + + const Internal::Obj::BaseObj& obj = dict; + std::string res = DumpStr(obj, config); + EXPECT_EQ(res, expOut); + + res.clear(); + JsonWriterOrdDictT::Write( + std::back_inserter(res), + dict, + config, WriterStates() + ); + EXPECT_EQ(res, expOut); + } + + config.m_indent = "\t"; + + { + std::string expOut = +"{\n\ + \"0\" : 0,\n\ + \"1\" : 1,\n\ + \"2\" : 2,\n\ + \"a\" : \"a\",\n\ + \"b\" : \"b\",\n\ + \"c\" : \"c\"\n\ +}"; + _Dict dict; + dict[_Str("a")] = _Str("a"); + dict[_Str("b")] = _Str("b"); + dict[_Str("c")] = _Str("c"); + dict[_Str("0")] = Internal::Obj::Int64(0); + dict[_Str("1")] = Internal::Obj::Int64(1); + dict[_Str("2")] = Internal::Obj::Int64(2); + + const Internal::Obj::BaseObj& obj = dict; + std::string res = DumpStr(obj, config); + EXPECT_EQ(res, expOut); + + res.clear(); + JsonWriterOrdDictT::Write( + std::back_inserter(res), + dict, + config, WriterStates() + ); + EXPECT_EQ(res, expOut); + } +} diff --git a/test/src/TestListParser.cpp b/test/src/TestListParser.cpp index cc771c8..4bb9f36 100644 --- a/test/src/TestListParser.cpp +++ b/test/src/TestListParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestNullParser.cpp b/test/src/TestNullParser.cpp index ce72f28..3b8bbab 100644 --- a/test/src/TestNullParser.cpp +++ b/test/src/TestNullParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestNumericParser.cpp b/test/src/TestNumericParser.cpp index ee1702b..61e28b6 100644 --- a/test/src/TestNumericParser.cpp +++ b/test/src/TestNumericParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestSpecialParser.cpp b/test/src/TestSpecialParser.cpp index 9aff5e8..148f4b6 100644 --- a/test/src/TestSpecialParser.cpp +++ b/test/src/TestSpecialParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestStaticDict.cpp b/test/src/TestStaticDict.cpp index 18250d0..5468c06 100644 --- a/test/src/TestStaticDict.cpp +++ b/test/src/TestStaticDict.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE diff --git a/test/src/TestStringParser.cpp b/test/src/TestStringParser.cpp index 5ce9e21..580ecd1 100644 --- a/test/src/TestStringParser.cpp +++ b/test/src/TestStringParser.cpp @@ -5,6 +5,9 @@ #include +#ifdef _MSC_VER +#include +#endif // _MSC_VER #include #ifndef SIMPLEJSON_CUSTOMIZED_NAMESPACE