mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Extracted interface JsonSink.
This commit is contained in:
		| @@ -37,9 +37,10 @@ private: | ||||
|     JsonValue items[N]; | ||||
|     int itemCount; | ||||
|  | ||||
|     virtual void writeTo(StringBuilder& sb) | ||||
|     virtual void writeTo(JsonSink& sb) | ||||
|     { | ||||
|         sb.append("["); | ||||
|         sb.reserveRoom(1); | ||||
|  | ||||
|         for (int i = 0; i < itemCount; i++) | ||||
|         { | ||||
| @@ -47,6 +48,7 @@ private: | ||||
|             items[i].writeTo(sb); | ||||
|         } | ||||
|  | ||||
|         sb.releaseRoom(1); | ||||
|         sb.append("]"); | ||||
|     } | ||||
| }; | ||||
|   | ||||
| @@ -86,13 +86,13 @@ | ||||
|     <ClCompile Include="JsonHashTableTests.cpp" /> | ||||
|     <ClCompile Include="JsonValue.cpp" /> | ||||
|     <ClCompile Include="StringBuilder.cpp" /> | ||||
|     <ClCompile Include="StringBuilderAppendEscapedTests.cpp" /> | ||||
|     <ClCompile Include="StringBuilderAppendTests.cpp" /> | ||||
|     <ClCompile Include="JsonValueTests.cpp" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="JsonArray.h" /> | ||||
|     <ClInclude Include="JsonHashTable.h" /> | ||||
|     <ClInclude Include="JsonObjectBase.h" /> | ||||
|     <ClInclude Include="JsonSink.h" /> | ||||
|     <ClInclude Include="JsonValue.h" /> | ||||
|     <ClInclude Include="StringBuilder.h" /> | ||||
|   </ItemGroup> | ||||
|   | ||||
| @@ -21,23 +21,17 @@ | ||||
|     <ClCompile Include="StringBuilder.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="StringBuilderAppendEscapedTests.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="StringBuilderAppendTests.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="JsonHashTableTests.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="JsonValue.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="JsonValueTests.cpp"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="JsonArray.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="StringBuilder.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
| @@ -50,5 +44,11 @@ | ||||
|     <ClInclude Include="JsonValue.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="JsonArray.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="JsonSink.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| @@ -45,19 +45,24 @@ private: | ||||
|     KeyValuePair items[N]; | ||||
|     int itemCount; | ||||
|  | ||||
|     virtual void writeTo(StringBuilder& sb) | ||||
|     virtual void writeTo(JsonSink& sink) | ||||
|     { | ||||
|         sb.append("{"); | ||||
|         sink.append("{"); | ||||
|         sink.reserveRoom(1); | ||||
|  | ||||
|         for (int i = 0; i < itemCount; i++) | ||||
|         { | ||||
|             if (i>0) sb.append(","); | ||||
|             sb.appendEscaped(items[i].key); | ||||
|             sb.append(":"); | ||||
|             items[i].value.writeTo(sb); | ||||
|             if (i>0) sink.append(","); | ||||
|  | ||||
|             JsonValue key(items[i].key); | ||||
|  | ||||
|             key.writeTo(sink); | ||||
|             sink.append(":"); | ||||
|             items[i].value.writeTo(sink); | ||||
|         } | ||||
|  | ||||
|         sb.append("}"); | ||||
|         sink.releaseRoom(1); | ||||
|         sink.append("}"); | ||||
|     } | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonValue.h" | ||||
| #include "JsonSink.h" | ||||
|  | ||||
| class JsonObjectBase | ||||
| { | ||||
| @@ -17,6 +18,6 @@ public: | ||||
|         writeTo(sb); | ||||
|     } | ||||
|  | ||||
|     virtual void writeTo(StringBuilder& sb) = 0; | ||||
|     virtual void writeTo(JsonSink& sb) = 0; | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										19
									
								
								JsonGeneratorTests/JsonSink.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								JsonGeneratorTests/JsonSink.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
|  * Arduino JSON library | ||||
|  * Benoit Blanchon 2014 - MIT License | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| class JsonSink | ||||
| { | ||||
| public: | ||||
|  | ||||
|     virtual void append(char c) = 0; | ||||
|     virtual void append(const char* s) = 0; | ||||
|  | ||||
|     virtual bool hasRoomFor(int n) = 0; | ||||
|     virtual void reserveRoom(int n) = 0; | ||||
|     virtual void releaseRoom(int n) = 0; | ||||
| }; | ||||
|  | ||||
| @@ -5,26 +5,88 @@ | ||||
|  | ||||
| #include "JsonValue.h" | ||||
| #include "JsonObjectBase.h" | ||||
| #include <cstdio> | ||||
| #include <cstring> | ||||
|  | ||||
| void JsonValue::writeBooleanTo(StringBuilder& sb) | ||||
| void JsonValue::writeBooleanTo(JsonSink& sb) | ||||
| { | ||||
|     sb.append(content.boolean ? "true" : "false"); | ||||
| } | ||||
|  | ||||
| void JsonValue::writeNumberTo(StringBuilder& sb) | ||||
| void JsonValue::writeNumberTo(JsonSink& sb) | ||||
| { | ||||
|     sb.append(content.number); | ||||
|     char tmp[16]; | ||||
|  | ||||
|     _snprintf(tmp, sizeof(tmp), "%lg", content.number); | ||||
|  | ||||
|     sb.append(tmp); | ||||
| } | ||||
|  | ||||
| void JsonValue::writeObjectTo(StringBuilder& sb) | ||||
| void JsonValue::writeObjectTo(JsonSink& sink) | ||||
| { | ||||
|     if (content.object) | ||||
|         ((JsonObjectBase*) content.object)->writeTo(sb); | ||||
|         ((JsonObjectBase*) content.object)->writeTo(sink); | ||||
|     else | ||||
|         sb.append("null"); | ||||
|         sink.append("null"); | ||||
| } | ||||
|  | ||||
| void JsonValue::writeStringTo(StringBuilder& sb) | ||||
| void JsonValue::writeStringTo(JsonSink& sink) | ||||
| { | ||||
|     sb.appendEscaped(content.string); | ||||
|     auto s = content.string; | ||||
|  | ||||
|     if (!s) | ||||
|     { | ||||
|         return sink.append("null"); | ||||
|     } | ||||
|  | ||||
|     if (!sink.hasRoomFor(2)) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     sink.append('\"'); | ||||
|     sink.reserveRoom(1); | ||||
|  | ||||
|     while (*s) | ||||
|     { | ||||
|         switch (*s) | ||||
|         { | ||||
|         case '"': | ||||
|             sink.append("\\\""); | ||||
|             break; | ||||
|  | ||||
|         case '\\': | ||||
|             sink.append("\\\\"); | ||||
|             break; | ||||
|  | ||||
|         case '\b': | ||||
|             sink.append("\\b"); | ||||
|             break; | ||||
|  | ||||
|         case '\f': | ||||
|             sink.append("\\f"); | ||||
|             break; | ||||
|  | ||||
|         case '\n': | ||||
|             sink.append("\\n"); | ||||
|             break; | ||||
|  | ||||
|         case '\r': | ||||
|             sink.append("\\r"); | ||||
|             break; | ||||
|  | ||||
|         case '\t': | ||||
|             sink.append("\\t"); | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             sink.append(*s); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         s++; | ||||
|     } | ||||
|  | ||||
|     sink.releaseRoom(1); | ||||
|     sink.append('\"'); | ||||
| } | ||||
| @@ -41,10 +41,10 @@ public: | ||||
|         content.object = &value; | ||||
|     } | ||||
|  | ||||
|     void writeTo(StringBuilder& sb) | ||||
|     void writeTo(JsonSink& sink) | ||||
|     { | ||||
|         // handmade polymorphism | ||||
|        (this->*implementation)(sb); | ||||
|         (this->*implementation)(sink); | ||||
|     } | ||||
|      | ||||
| private: | ||||
| @@ -59,10 +59,10 @@ private: | ||||
|  | ||||
|     Content content; | ||||
|  | ||||
|     void (JsonValue::*implementation)(StringBuilder& sb); | ||||
|     void (JsonValue::*implementation)(JsonSink& sb); | ||||
|  | ||||
|     void writeBooleanTo(StringBuilder& sb); | ||||
|     void writeNumberTo(StringBuilder& sb); | ||||
|     void writeObjectTo(StringBuilder& sb); | ||||
|     void writeStringTo(StringBuilder& sb); | ||||
|     void writeBooleanTo(JsonSink& sb); | ||||
|     void writeNumberTo(JsonSink& sb); | ||||
|     void writeObjectTo(JsonSink& sb); | ||||
|     void writeStringTo(JsonSink& sb); | ||||
| }; | ||||
| @@ -1,11 +1,12 @@ | ||||
| #include "CppUnitTest.h" | ||||
| #include "StringBuilder.h" | ||||
| #include "JsonValue.h" | ||||
| 
 | ||||
| using namespace Microsoft::VisualStudio::CppUnitTestFramework; | ||||
| 
 | ||||
| namespace JsonGeneratorTests | ||||
| { | ||||
|     TEST_CLASS(StringBuilderAppendEscapedTests) | ||||
|     TEST_CLASS(JsonValueTests) | ||||
|     { | ||||
|         char buffer[20]; | ||||
|         StringBuilder* sb; | ||||
| @@ -16,24 +17,24 @@ namespace JsonGeneratorTests | ||||
|         { | ||||
|             sb = new StringBuilder(buffer, sizeof(buffer)); | ||||
|         } | ||||
|          | ||||
|                  | ||||
|         TEST_METHOD(InitialState) | ||||
|         { | ||||
|             assertResultIs(""); | ||||
|         } | ||||
| 
 | ||||
|         TEST_METHOD(Null) | ||||
|         { | ||||
|             append((char*)0); | ||||
|             assertResultIs("null"); | ||||
|         } | ||||
| 
 | ||||
|         TEST_METHOD(EmptyString) | ||||
|         { | ||||
|             append(""); | ||||
|             assertResultIs("\"\""); | ||||
|         } | ||||
| 
 | ||||
|         TEST_METHOD(Null) | ||||
|         { | ||||
|             append(NULL); | ||||
|             assertResultIs("null"); | ||||
|         } | ||||
| 
 | ||||
|         TEST_METHOD(OneString) | ||||
|         { | ||||
|             append("ABCD"); | ||||
| @@ -55,16 +56,23 @@ namespace JsonGeneratorTests | ||||
|             append(""); | ||||
|             assertResultIs("\"ABCDEFGHIJKLMNOPQ\""); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         TEST_METHOD(SpecialChars) | ||||
|         { | ||||
|             append("\\\"\b\f\n\r\t"); | ||||
|             assertResultIs("\"\\\\\\\"\\b\\f\\n\\r\\t\""); | ||||
|         } | ||||
|          | ||||
|         void append(const char* s) | ||||
| 
 | ||||
|         TEST_METHOD(Number) | ||||
|         { | ||||
|             sb->appendEscaped(s); | ||||
|             append(3.14); | ||||
|             assertResultIs("3.14"); | ||||
|         } | ||||
| 
 | ||||
|         template<typename T> | ||||
|         void append(T value) | ||||
|         { | ||||
|             JsonValue(value).writeTo(*sb); | ||||
|         } | ||||
| 
 | ||||
|         void assertResultIs(const char* expected) | ||||
| @@ -3,27 +3,10 @@ | ||||
|  * Benoit Blanchon 2014 - MIT License | ||||
|  */ | ||||
|  | ||||
| #include <cstdio> | ||||
| #include <cstring> | ||||
|  | ||||
| #include "StringBuilder.h" | ||||
|  | ||||
| void StringBuilder::append(double value) | ||||
| { | ||||
|     char* tail = buffer + length; | ||||
|  | ||||
|     _snprintf(tail, capacity - length, "%lg", value); | ||||
|  | ||||
|     length += strlen(tail); | ||||
| } | ||||
|  | ||||
| void StringBuilder::append(const char* s) | ||||
| { | ||||
|     if (!s) | ||||
|     { | ||||
|         return append("null");         | ||||
|     } | ||||
|  | ||||
|     char* tail = buffer + length; | ||||
|  | ||||
|     while (*s && length<capacity) | ||||
| @@ -34,67 +17,11 @@ void StringBuilder::append(const char* s) | ||||
|     buffer[length] = 0; | ||||
| } | ||||
|  | ||||
| void StringBuilder::appendEscaped(const char* s) | ||||
|  | ||||
| void StringBuilder::append(char c) | ||||
| { | ||||
|     if (!s) | ||||
|     { | ||||
|         return append("null"); | ||||
|     } | ||||
|     if (length >= capacity) return; | ||||
|  | ||||
|     if (length > capacity - 2) | ||||
|     { | ||||
|         // not enough from for quotes | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     buffer[length++] = '"'; | ||||
|  | ||||
|     // keep one slot for the end quote | ||||
|     capacity--; | ||||
|  | ||||
|     while (*s && length < capacity) | ||||
|     { | ||||
|         switch (*s) | ||||
|         { | ||||
|         case '"': | ||||
|             append("\\\""); | ||||
|             break; | ||||
|  | ||||
|         case '\\': | ||||
|             append("\\\\"); | ||||
|             break; | ||||
|  | ||||
|         case '\b': | ||||
|             append("\\b"); | ||||
|             break; | ||||
|  | ||||
|         case '\f': | ||||
|             append("\\f"); | ||||
|             break; | ||||
|  | ||||
|         case '\n': | ||||
|             append("\\n"); | ||||
|             break; | ||||
|  | ||||
|         case '\r': | ||||
|             append("\\r"); | ||||
|             break; | ||||
|  | ||||
|         case '\t': | ||||
|             append("\\t"); | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             buffer[length++] = *s; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         s++; | ||||
|     } | ||||
|  | ||||
|     buffer[length++] = '"'; | ||||
|     buffer[length++] = c; | ||||
|     buffer[length] = 0; | ||||
|  | ||||
|     // restore the original capacity | ||||
|     capacity++; | ||||
| } | ||||
| @@ -5,22 +5,38 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| class StringBuilder | ||||
| #include "JsonSink.h" | ||||
|  | ||||
| class StringBuilder : public JsonSink | ||||
| { | ||||
| public: | ||||
|     StringBuilder(char* buf, size_t size) | ||||
|     StringBuilder(char* buf, int size) | ||||
|         : buffer(buf), capacity(size-1), length(0) | ||||
|     { | ||||
|         buffer[0] = 0; | ||||
|     } | ||||
|  | ||||
|     void append(double); | ||||
|     void append(const char* s); | ||||
|     void appendEscaped(const char* s); | ||||
|     virtual void append(char c); | ||||
|     virtual void append(const char* s); | ||||
|  | ||||
|     virtual bool hasRoomFor(int n) | ||||
|     { | ||||
|         return capacity - length >= n; | ||||
|     } | ||||
|  | ||||
|     virtual void reserveRoom(int n) | ||||
|     { | ||||
|         capacity -= n; | ||||
|     } | ||||
|  | ||||
|     virtual void releaseRoom(int n) | ||||
|     { | ||||
|         capacity += n; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     char* buffer; | ||||
|     size_t capacity; | ||||
|     size_t length; | ||||
|     int capacity; | ||||
|     int length; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,83 +0,0 @@ | ||||
| #include "CppUnitTest.h" | ||||
| #include "StringBuilder.h" | ||||
|  | ||||
| using namespace Microsoft::VisualStudio::CppUnitTestFramework; | ||||
|  | ||||
| namespace JsonGeneratorTests | ||||
| { | ||||
|     TEST_CLASS(StringBuilderAppendTests) | ||||
|     { | ||||
|         char buffer[16]; | ||||
|         StringBuilder* sb; | ||||
|  | ||||
|     public: | ||||
|  | ||||
|         TEST_METHOD_INITIALIZE(Initialize) | ||||
|         { | ||||
|             sb = new StringBuilder(buffer, sizeof(buffer)); | ||||
|         } | ||||
|          | ||||
|         TEST_METHOD(InitialState) | ||||
|         { | ||||
|             assertResultIs(""); | ||||
|         } | ||||
|  | ||||
|         TEST_METHOD(EmptyString) | ||||
|         { | ||||
|             append(""); | ||||
|             assertResultIs(""); | ||||
|         } | ||||
|          | ||||
|         TEST_METHOD(Null) | ||||
|         { | ||||
|             append((char*)0); | ||||
|             assertResultIs("null"); | ||||
|         } | ||||
|  | ||||
|         TEST_METHOD(Number) | ||||
|         { | ||||
|             append(3.14); | ||||
|             assertResultIs("3.14"); | ||||
|         } | ||||
|  | ||||
|         TEST_METHOD(OneString) | ||||
|         { | ||||
|             append("ABCD"); | ||||
|             assertResultIs("ABCD"); | ||||
|         } | ||||
|  | ||||
|         TEST_METHOD(TwoStrings) | ||||
|         { | ||||
|             append("ABCD"); | ||||
|             append("EFGH"); | ||||
|             assertResultIs("ABCDEFGH"); | ||||
|         } | ||||
|  | ||||
|         TEST_METHOD(OverCapacity) | ||||
|         { | ||||
|             append("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); | ||||
|             assertResultIs("ABCDEFGHIJKLMNO"); | ||||
|         } | ||||
|  | ||||
|         TEST_METHOD(SpecialChars) | ||||
|         { | ||||
|             append("\\\"\b\f\n\r"); | ||||
|             assertResultIs("\\\"\b\f\n\r"); | ||||
|         } | ||||
|  | ||||
|         void append(double d) | ||||
|         { | ||||
|             sb->append(d); | ||||
|         } | ||||
|  | ||||
|         void append(const char* s) | ||||
|         { | ||||
|             sb->append(s); | ||||
|         } | ||||
|  | ||||
|         void assertResultIs(const char* expected) | ||||
|         { | ||||
|             Assert::AreEqual(expected, buffer); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user