Explorar el Código

Removed `Print` class and converted `printTo()` to a template method (issue #276)

Benoit Blanchon hace 8 años
padre
commit
9afa05e2f4

+ 2 - 0
CHANGELOG.md

@@ -9,6 +9,8 @@ HEAD
 * Renamed `JsonArray::removeAt(size_t)` into `remove(size_t)`
 * Renamed folder `include/` to `src/`
 * Fixed warnings `floating constant exceeds range of float`and `floating constant truncated to zero` (issue #483)
+* Removed `Print` class and converted `printTo()` to a template method (issue #276)
+* Removed example `IndentedPrintExample.ino`
 
 v5.8.4
 ------

+ 0 - 35
examples/IndentedPrintExample/IndentedPrintExample.ino

@@ -1,35 +0,0 @@
-// Copyright Benoit Blanchon 2014-2017
-// MIT License
-//
-// Arduino JSON library
-// https://bblanchon.github.io/ArduinoJson/
-// If you like this project, please add a star!
-
-#include <ArduinoJson.h>
-
-using namespace ArduinoJson::Internals;
-
-void setup() {
-  Serial.begin(9600);
-  while (!Serial) {
-    // wait serial port initialization
-  }
-
-  IndentedPrint serial(Serial);
-  serial.setTabSize(4);
-
-  serial.println("This is at indentation 0");
-  serial.indent();
-  serial.println("This is at indentation 1");
-  serial.println("This is also at indentation 1");
-  serial.indent();
-  serial.println("This is at indentation 2");
-
-  serial.unindent();
-  serial.unindent();
-  serial.println("This is back at indentation 0");
-}
-
-void loop() {
-  // not used in this example
-}

+ 0 - 2
src/ArduinoJson/Data/Encoding.hpp

@@ -7,8 +7,6 @@
 
 #pragma once
 
-#include "../Print.hpp"
-
 namespace ArduinoJson {
 namespace Internals {
 

+ 2 - 2
src/ArduinoJson/JsonVariant.hpp

@@ -40,8 +40,8 @@ class JsonObject;
 // - a string (const char*)
 // - a reference to a JsonArray or JsonObject
 class JsonVariant : public JsonVariantBase<JsonVariant> {
-  friend void Internals::JsonSerializer::serialize(const JsonVariant &,
-                                                   JsonWriter &);
+  template <typename Print>
+  friend class Internals::JsonSerializer;
 
  public:
   // Creates an uninitialized JsonVariant

+ 0 - 44
src/ArduinoJson/Print.hpp

@@ -1,44 +0,0 @@
-// Copyright Benoit Blanchon 2014-2017
-// MIT License
-//
-// Arduino JSON library
-// https://bblanchon.github.io/ArduinoJson/
-// If you like this project, please add a star!
-
-#pragma once
-
-#ifndef ARDUINO
-
-#include <stddef.h>
-#include <stdint.h>
-
-namespace ArduinoJson {
-// This class reproduces Arduino's Print class
-class Print {
- public:
-  virtual ~Print() {}
-
-  virtual size_t write(uint8_t) = 0;
-
-  size_t print(const char* s) {
-    size_t n = 0;
-    while (*s) {
-      n += write(static_cast<uint8_t>(*s++));
-    }
-    return n;
-  }
-
-  size_t println() {
-    size_t n = 0;
-    n += write('\r');
-    n += write('\n');
-    return n;
-  }
-};
-}
-
-#else
-
-#include <Print.h>
-
-#endif

+ 6 - 4
src/ArduinoJson/Serialization/DummyPrint.hpp

@@ -7,17 +7,19 @@
 
 #pragma once
 
-#include "../Print.hpp"
-
 namespace ArduinoJson {
 namespace Internals {
 
 // A dummy Print implementation used in JsonPrintable::measureLength()
-class DummyPrint : public Print {
+class DummyPrint {
  public:
-  virtual size_t write(uint8_t) {
+  size_t print(char) {
     return 1;
   }
+
+  size_t print(const char* s) {
+    return strlen(s);
+  }
 };
 }
 }

+ 9 - 4
src/ArduinoJson/Serialization/DynamicStringBuilder.hpp

@@ -7,7 +7,6 @@
 
 #pragma once
 
-#include "../Print.hpp"
 #include "../StringTraits/StringTraits.hpp"
 
 namespace ArduinoJson {
@@ -15,15 +14,21 @@ namespace Internals {
 
 // A Print implementation that allows to write in a String
 template <typename TString>
-class DynamicStringBuilder : public Print {
+class DynamicStringBuilder {
  public:
   DynamicStringBuilder(TString &str) : _str(str) {}
 
-  virtual size_t write(uint8_t c) {
-    StringTraits<TString>::append(_str, static_cast<char>(c));
+  size_t print(char c) {
+    StringTraits<TString>::append(_str, c);
     return 1;
   }
 
+  size_t print(const char *s) {
+    size_t initialLen = _str.length();
+    StringTraits<TString>::append(_str, s);
+    return _str.length() - initialLen;
+  }
+
  private:
   DynamicStringBuilder &operator=(const DynamicStringBuilder &);
 

+ 12 - 6
src/ArduinoJson/Serialization/IndentedPrint.hpp

@@ -7,15 +7,14 @@
 
 #pragma once
 
-#include "../Print.hpp"
-
 namespace ArduinoJson {
 namespace Internals {
 
 // Decorator on top of Print to allow indented output.
 // This class is used by JsonPrintable::prettyPrintTo() but can also be used
 // for your own purpose, like logging.
-class IndentedPrint : public Print {
+template <typename Print>
+class IndentedPrint {
  public:
   explicit IndentedPrint(Print &p) : sink(&p) {
     level = 0;
@@ -23,14 +22,21 @@ class IndentedPrint : public Print {
     isNewLine = true;
   }
 
-  virtual size_t write(uint8_t c) {
+  size_t print(char c) {
     size_t n = 0;
     if (isNewLine) n += writeTabs();
-    n += sink->write(c);
+    n += sink->print(c);
     isNewLine = c == '\n';
     return n;
   }
 
+  size_t print(const char *s) {
+    // TODO: optimize
+    size_t n = 0;
+    while (*s) n += print(*s++);
+    return n;
+  }
+
   // Adds one level of indentation
   void indent() {
     if (level < MAX_LEVEL) level++;
@@ -54,7 +60,7 @@ class IndentedPrint : public Print {
 
   size_t writeTabs() {
     size_t n = 0;
-    for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
+    for (int i = 0; i < level * tabSize; i++) n += sink->print(' ');
     return n;
   }
 

+ 14 - 7
src/ArduinoJson/Serialization/JsonPrintable.hpp

@@ -31,9 +31,12 @@ namespace Internals {
 template <typename T>
 class JsonPrintable {
  public:
-  size_t printTo(Print &print) const {
-    JsonWriter writer(print);
-    JsonSerializer::serialize(downcast(), writer);
+  template <typename Print>
+  typename TypeTraits::EnableIf<!TypeTraits::IsString<Print>::value,
+                                size_t>::type
+  printTo(Print &print) const {
+    JsonWriter<Print> writer(print);
+    JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer);
     return writer.bytesWritten();
   }
 
@@ -62,8 +65,9 @@ class JsonPrintable {
     return printTo(sb);
   }
 
-  size_t prettyPrintTo(IndentedPrint &print) const {
-    Prettyfier p(print);
+  template <typename Print>
+  size_t prettyPrintTo(IndentedPrint<Print> &print) const {
+    Prettyfier<Print> p(print);
     return printTo(p);
   }
 
@@ -77,8 +81,11 @@ class JsonPrintable {
     return prettyPrintTo(buffer, N);
   }
 
-  size_t prettyPrintTo(Print &print) const {
-    IndentedPrint indentedPrint = IndentedPrint(print);
+  template <typename Print>
+  typename TypeTraits::EnableIf<!TypeTraits::IsString<Print>::value,
+                                size_t>::type
+  prettyPrintTo(Print &print) const {
+    IndentedPrint<Print> indentedPrint(print);
     return prettyPrintTo(indentedPrint);
   }
 

+ 6 - 5
src/ArduinoJson/Serialization/JsonSerializer.hpp

@@ -20,14 +20,15 @@ class JsonVariant;
 
 namespace Internals {
 
+template <typename Writer>
 class JsonSerializer {
  public:
-  static void serialize(const JsonArray &, JsonWriter &);
-  static void serialize(const JsonArraySubscript &, JsonWriter &);
-  static void serialize(const JsonObject &, JsonWriter &);
+  static void serialize(const JsonArray &, Writer &);
+  static void serialize(const JsonArraySubscript &, Writer &);
+  static void serialize(const JsonObject &, Writer &);
   template <typename TKey>
-  static void serialize(const JsonObjectSubscript<TKey> &, JsonWriter &);
-  static void serialize(const JsonVariant &, JsonWriter &);
+  static void serialize(const JsonObjectSubscript<TKey> &, Writer &);
+  static void serialize(const JsonVariant &, Writer &);
 };
 }
 }

+ 15 - 10
src/ArduinoJson/Serialization/JsonSerializerImpl.hpp

@@ -14,8 +14,9 @@
 #include "../JsonVariant.hpp"
 #include "JsonSerializer.hpp"
 
-inline void ArduinoJson::Internals::JsonSerializer::serialize(
-    const JsonArray& array, JsonWriter& writer) {
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonArray& array, Writer& writer) {
   writer.beginArray();
 
   JsonArray::const_iterator it = array.begin();
@@ -31,13 +32,15 @@ inline void ArduinoJson::Internals::JsonSerializer::serialize(
   writer.endArray();
 }
 
-inline void ArduinoJson::Internals::JsonSerializer::serialize(
-    const JsonArraySubscript& arraySubscript, JsonWriter& writer) {
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonArraySubscript& arraySubscript, Writer& writer) {
   serialize(arraySubscript.as<JsonVariant>(), writer);
 }
 
-inline void ArduinoJson::Internals::JsonSerializer::serialize(
-    const JsonObject& object, JsonWriter& writer) {
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonObject& object, Writer& writer) {
   writer.beginObject();
 
   JsonObject::const_iterator it = object.begin();
@@ -55,14 +58,16 @@ inline void ArduinoJson::Internals::JsonSerializer::serialize(
   writer.endObject();
 }
 
+template <typename Writer>
 template <typename TKey>
-inline void ArduinoJson::Internals::JsonSerializer::serialize(
-    const JsonObjectSubscript<TKey>& objectSubscript, JsonWriter& writer) {
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonObjectSubscript<TKey>& objectSubscript, Writer& writer) {
   serialize(objectSubscript.template as<JsonVariant>(), writer);
 }
 
-inline void ArduinoJson::Internals::JsonSerializer::serialize(
-    const JsonVariant& variant, JsonWriter& writer) {
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonVariant& variant, Writer& writer) {
   switch (variant._type) {
     case JSON_UNDEFINED:
       return;

+ 3 - 2
src/ArduinoJson/Serialization/JsonWriter.hpp

@@ -7,13 +7,13 @@
 
 #pragma once
 
+#include <stdint.h>
 #include "../Data/Encoding.hpp"
 #include "../Data/JsonFloat.hpp"
 #include "../Data/JsonInteger.hpp"
 #include "../Polyfills/attributes.hpp"
 #include "../Polyfills/math.hpp"
 #include "../Polyfills/normalize.hpp"
-#include "../Print.hpp"
 
 namespace ArduinoJson {
 namespace Internals {
@@ -25,6 +25,7 @@ namespace Internals {
 // - JsonVariant::writeTo()
 // Its derived by PrettyJsonWriter that overrides some members to add
 // indentation.
+template <typename Print>
 class JsonWriter {
  public:
   explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
@@ -150,7 +151,7 @@ class JsonWriter {
     _length += _sink.print(s);
   }
   void writeRaw(char c) {
-    _length += _sink.write(c);
+    _length += _sink.print(c);
   }
 
  protected:

+ 27 - 21
src/ArduinoJson/Serialization/Prettyfier.hpp

@@ -13,19 +13,27 @@ namespace ArduinoJson {
 namespace Internals {
 
 // Converts a compact JSON string into an indented one.
-class Prettyfier : public Print {
+template <typename Print>
+class Prettyfier {
  public:
-  explicit Prettyfier(IndentedPrint& p) : _sink(p) {
+  explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) {
     _previousChar = 0;
     _inString = false;
   }
 
-  virtual size_t write(uint8_t c) {
+  size_t print(char c) {
     size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
     _previousChar = c;
     return n;
   }
 
+  size_t print(const char* s) {
+    // TODO: optimize
+    size_t n = 0;
+    while (*s) n += print(*s++);
+    return n;
+  }
+
  private:
   Prettyfier& operator=(const Prettyfier&);  // cannot be assigned
 
@@ -33,15 +41,15 @@ class Prettyfier : public Print {
     return _previousChar == '{' || _previousChar == '[';
   }
 
-  size_t handleStringChar(uint8_t c) {
+  size_t handleStringChar(char c) {
     bool isQuote = c == '"' && _previousChar != '\\';
 
     if (isQuote) _inString = false;
 
-    return _sink.write(c);
+    return _sink.print(c);
   }
 
-  size_t handleMarkupChar(uint8_t c) {
+  size_t handleMarkupChar(char c) {
     switch (c) {
       case '{':
       case '[':
@@ -65,31 +73,29 @@ class Prettyfier : public Print {
     }
   }
 
-  size_t writeBlockClose(uint8_t c) {
+  size_t writeBlockClose(char c) {
     size_t n = 0;
     n += unindentIfNeeded();
-    n += _sink.write(c);
+    n += _sink.print(c);
     return n;
   }
 
-  size_t writeBlockOpen(uint8_t c) {
+  size_t writeBlockOpen(char c) {
     size_t n = 0;
     n += indentIfNeeded();
-    n += _sink.write(c);
+    n += _sink.print(c);
     return n;
   }
 
   size_t writeColon() {
     size_t n = 0;
-    n += _sink.write(':');
-    n += _sink.write(' ');
+    n += _sink.print(": ");
     return n;
   }
 
   size_t writeComma() {
     size_t n = 0;
-    n += _sink.write(',');
-    n += _sink.println();
+    n += _sink.print(",\r\n");
     return n;
   }
 
@@ -97,14 +103,14 @@ class Prettyfier : public Print {
     _inString = true;
     size_t n = 0;
     n += indentIfNeeded();
-    n += _sink.write('"');
+    n += _sink.print('"');
     return n;
   }
 
-  size_t writeNormalChar(uint8_t c) {
+  size_t writeNormalChar(char c) {
     size_t n = 0;
     n += indentIfNeeded();
-    n += _sink.write(c);
+    n += _sink.print(c);
     return n;
   }
 
@@ -112,18 +118,18 @@ class Prettyfier : public Print {
     if (!inEmptyBlock()) return 0;
 
     _sink.indent();
-    return _sink.println();
+    return _sink.print("\r\n");
   }
 
   size_t unindentIfNeeded() {
     if (inEmptyBlock()) return 0;
 
     _sink.unindent();
-    return _sink.println();
+    return _sink.print("\r\n");
   }
 
-  uint8_t _previousChar;
-  IndentedPrint& _sink;
+  char _previousChar;
+  IndentedPrint<Print>& _sink;
   bool _inString;
 };
 }

+ 16 - 14
src/ArduinoJson/Serialization/StaticStringBuilder.hpp

@@ -7,31 +7,33 @@
 
 #pragma once
 
-#include "../Print.hpp"
-
 namespace ArduinoJson {
 namespace Internals {
 
 // A Print implementation that allows to write in a char[]
-class StaticStringBuilder : public Print {
+class StaticStringBuilder {
  public:
-  StaticStringBuilder(char *buf, size_t size)
-      : buffer(buf), capacity(size - 1), length(0) {
-    buffer[0] = '\0';
+  StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) {
+    *p = '\0';
   }
 
-  virtual size_t write(uint8_t c) {
-    if (length >= capacity) return 0;
-
-    buffer[length++] = c;
-    buffer[length] = '\0';
+  size_t print(char c) {
+    if (p >= end) return 0;
+    *p++ = c;
+    *p = '\0';
     return 1;
   }
 
+  size_t print(const char *s) {
+    char *begin = p;
+    while (p < end && *s) *p++ = *s++;
+    *p = '\0';
+    return p - begin;
+  }
+
  private:
-  char *buffer;
-  size_t capacity;
-  size_t length;
+  char *end;
+  char *p;
 };
 }
 }

+ 8 - 5
src/ArduinoJson/Serialization/StreamPrintAdapter.hpp

@@ -11,22 +11,25 @@
 
 #if ARDUINOJSON_ENABLE_STD_STREAM
 
-#include "../Print.hpp"
-
 #include <ostream>
 
 namespace ArduinoJson {
 namespace Internals {
 
-class StreamPrintAdapter : public Print {
+class StreamPrintAdapter {
  public:
   explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
 
-  virtual size_t write(uint8_t c) {
-    _os << static_cast<char>(c);
+  size_t print(char c) {
+    _os << c;
     return 1;
   }
 
+  size_t print(const char* s) {
+    _os << s;
+    return strlen(s);
+  }
+
  private:
   // cannot be assigned
   StreamPrintAdapter& operator=(const StreamPrintAdapter&);

+ 4 - 0
src/ArduinoJson/StringTraits/StdString.hpp

@@ -43,6 +43,10 @@ struct StdStringTraits {
     str += c;
   }
 
+  static void append(TString& str, const char* s) {
+    str += s;
+  }
+
   static const bool has_append = true;
   static const bool has_equals = true;
   static const bool should_duplicate = true;

+ 1 - 1
test/JsonWriter/writeFloat.cpp

@@ -17,7 +17,7 @@ using namespace ArduinoJson::Internals;
 void check(const std::string& expected, double input, uint8_t digits = 2) {
   char output[1024];
   StaticStringBuilder sb(output, sizeof(output));
-  JsonWriter writer(sb);
+  JsonWriter<StaticStringBuilder> writer(sb);
   writer.writeFloat(input, digits);
   REQUIRE(output == expected);
   REQUIRE(writer.bytesWritten() == expected.size());

+ 1 - 1
test/JsonWriter/writeString.cpp

@@ -15,7 +15,7 @@ using namespace ArduinoJson::Internals;
 void check(const char* input, std::string expected) {
   char output[1024];
   StaticStringBuilder sb(output, sizeof(output));
-  JsonWriter writer(sb);
+  JsonWriter<StaticStringBuilder> writer(sb);
   writer.writeString(input);
   REQUIRE(expected == output);
   REQUIRE(writer.bytesWritten() == expected.size());

+ 21 - 10
test/Misc/StringBuilder.cpp

@@ -10,20 +10,12 @@
 
 using namespace ArduinoJson::Internals;
 
-TEST_CASE("StringBuilder") {
-  char output[20];
-  StaticStringBuilder sb(output, sizeof(output));
-
+template <typename StringBuilder, typename String>
+void common_tests(StringBuilder& sb, const String& output) {
   SECTION("InitialState") {
     REQUIRE(std::string("") == output);
   }
 
-  SECTION("OverCapacity") {
-    REQUIRE(19 == sb.print("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
-    REQUIRE(0 == sb.print("ABC"));
-    REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output);
-  }
-
   SECTION("EmptyString") {
     REQUIRE(0 == sb.print(""));
     REQUIRE(std::string("") == output);
@@ -40,3 +32,22 @@ TEST_CASE("StringBuilder") {
     REQUIRE(std::string("ABCDEFGH") == output);
   }
 }
+
+TEST_CASE("StaticStringBuilder") {
+  char output[20];
+  StaticStringBuilder sb(output, sizeof(output));
+
+  common_tests(sb, static_cast<const char*>(output));
+
+  SECTION("OverCapacity") {
+    REQUIRE(19 == sb.print("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+    REQUIRE(0 == sb.print("ABC"));
+    REQUIRE(std::string("ABCDEFGHIJKLMNOPQRS") == output);
+  }
+}
+
+TEST_CASE("DynamicStringBuilder") {
+  std::string output;
+  DynamicStringBuilder<std::string> sb(output);
+  common_tests(sb, output);
+}