diff --git a/JsonGeneratorTests/JsonArray.h b/JsonGeneratorTests/JsonArray.h
index 96d7aaa6..f3bc4564 100644
--- a/JsonGeneratorTests/JsonArray.h
+++ b/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("]");
}
};
diff --git a/JsonGeneratorTests/JsonGeneratorTests.vcxproj b/JsonGeneratorTests/JsonGeneratorTests.vcxproj
index 18e185bf..d50f2a04 100644
--- a/JsonGeneratorTests/JsonGeneratorTests.vcxproj
+++ b/JsonGeneratorTests/JsonGeneratorTests.vcxproj
@@ -86,13 +86,13 @@
-
-
+
+
diff --git a/JsonGeneratorTests/JsonGeneratorTests.vcxproj.filters b/JsonGeneratorTests/JsonGeneratorTests.vcxproj.filters
index b6aff73e..4a87129b 100644
--- a/JsonGeneratorTests/JsonGeneratorTests.vcxproj.filters
+++ b/JsonGeneratorTests/JsonGeneratorTests.vcxproj.filters
@@ -21,23 +21,17 @@
Source Files
-
- Source Files
-
-
- Source Files
-
Source Files
Source Files
+
+ Source Files
+
-
- Header Files
-
Header Files
@@ -50,5 +44,11 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/JsonGeneratorTests/JsonHashTable.h b/JsonGeneratorTests/JsonHashTable.h
index 878915ed..f5a58393 100644
--- a/JsonGeneratorTests/JsonHashTable.h
+++ b/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("}");
}
};
diff --git a/JsonGeneratorTests/JsonObjectBase.h b/JsonGeneratorTests/JsonObjectBase.h
index c9939250..fe9ee4e0 100644
--- a/JsonGeneratorTests/JsonObjectBase.h
+++ b/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;
};
diff --git a/JsonGeneratorTests/JsonSink.h b/JsonGeneratorTests/JsonSink.h
new file mode 100644
index 00000000..cd8344ac
--- /dev/null
+++ b/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;
+};
+
diff --git a/JsonGeneratorTests/JsonValue.cpp b/JsonGeneratorTests/JsonValue.cpp
index 032c28be..26bc42f0 100644
--- a/JsonGeneratorTests/JsonValue.cpp
+++ b/JsonGeneratorTests/JsonValue.cpp
@@ -5,26 +5,88 @@
#include "JsonValue.h"
#include "JsonObjectBase.h"
+#include
+#include
-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('\"');
}
\ No newline at end of file
diff --git a/JsonGeneratorTests/JsonValue.h b/JsonGeneratorTests/JsonValue.h
index 3f9d8f0b..1cf1ee6d 100644
--- a/JsonGeneratorTests/JsonValue.h
+++ b/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);
};
\ No newline at end of file
diff --git a/JsonGeneratorTests/StringBuilderAppendEscapedTests.cpp b/JsonGeneratorTests/JsonValueTests.cpp
similarity index 78%
rename from JsonGeneratorTests/StringBuilderAppendEscapedTests.cpp
rename to JsonGeneratorTests/JsonValueTests.cpp
index 96e07581..ecc0a2b3 100644
--- a/JsonGeneratorTests/StringBuilderAppendEscapedTests.cpp
+++ b/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,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
+ void append(T value)
+ {
+ JsonValue(value).writeTo(*sb);
}
void assertResultIs(const char* expected)
diff --git a/JsonGeneratorTests/StringBuilder.cpp b/JsonGeneratorTests/StringBuilder.cpp
index 610c9fc7..f7d2058b 100644
--- a/JsonGeneratorTests/StringBuilder.cpp
+++ b/JsonGeneratorTests/StringBuilder.cpp
@@ -3,27 +3,10 @@
* Benoit Blanchon 2014 - MIT License
*/
-#include
-#include
-
#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) 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++;
}
\ No newline at end of file
diff --git a/JsonGeneratorTests/StringBuilder.h b/JsonGeneratorTests/StringBuilder.h
index 83989c73..886ac063 100644
--- a/JsonGeneratorTests/StringBuilder.h
+++ b/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;
};
diff --git a/JsonGeneratorTests/StringBuilderAppendTests.cpp b/JsonGeneratorTests/StringBuilderAppendTests.cpp
deleted file mode 100644
index 0730d3a6..00000000
--- a/JsonGeneratorTests/StringBuilderAppendTests.cpp
+++ /dev/null
@@ -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);
- }
- };
-}
\ No newline at end of file