Przeglądaj źródła

Extracted interface JsonSink.

Benoît Blanchon 11 lat temu
rodzic
commit
69d682ce81

+ 3 - 1
JsonGeneratorTests/JsonArray.h

@@ -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("]");
     }
 };

+ 2 - 2
JsonGeneratorTests/JsonGeneratorTests.vcxproj

@@ -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>

+ 9 - 9
JsonGeneratorTests/JsonGeneratorTests.vcxproj.filters

@@ -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>

+ 12 - 7
JsonGeneratorTests/JsonHashTable.h

@@ -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("}");
     }
 };
 

+ 2 - 1
JsonGeneratorTests/JsonObjectBase.h

@@ -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 - 0
JsonGeneratorTests/JsonSink.h

@@ -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;
+};
+

+ 70 - 8
JsonGeneratorTests/JsonValue.cpp

@@ -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('\"');
 }

+ 7 - 7
JsonGeneratorTests/JsonValue.h

@@ -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);
 };

+ 20 - 12
JsonGeneratorTests/StringBuilderAppendEscapedTests.cpp → JsonGeneratorTests/JsonValueTests.cpp

@@ -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,22 +17,22 @@ namespace JsonGeneratorTests
         {
             sb = new StringBuilder(buffer, sizeof(buffer));
         }
-        
+                
         TEST_METHOD(InitialState)
         {
             assertResultIs("");
         }
 
-        TEST_METHOD(EmptyString)
+        TEST_METHOD(Null)
         {
-            append("");
-            assertResultIs("\"\"");
+            append((char*)0);
+            assertResultIs("null");
         }
 
-        TEST_METHOD(Null)
+        TEST_METHOD(EmptyString)
         {
-            append(NULL);
-            assertResultIs("null");
+            append("");
+            assertResultIs("\"\"");
         }
 
         TEST_METHOD(OneString)
@@ -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)
+        {
+            append(3.14);
+            assertResultIs("3.14");
+        }
+
+        template<typename T>
+        void append(T value)
         {
-            sb->appendEscaped(s);
+            JsonValue(value).writeTo(*sb);
         }
 
         void assertResultIs(const char* expected)

+ 4 - 77
JsonGeneratorTests/StringBuilder.cpp

@@ -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)
-{
-    if (!s)
-    {
-        return append("null");
-    }
-
-    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++;
-    }
+void StringBuilder::append(char c)
+{
+    if (length >= capacity) return;
 
-    buffer[length++] = '"';
+    buffer[length++] = c;
     buffer[length] = 0;
-
-    // restore the original capacity
-    capacity++;
 }

+ 23 - 7
JsonGeneratorTests/StringBuilder.h

@@ -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;
 };
 

+ 0 - 83
JsonGeneratorTests/StringBuilderAppendTests.cpp

@@ -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);
-        }
-    };
-}