浏览代码

Removed the indirection via StringSlot

Benoit Blanchon 7 年之前
父节点
当前提交
a60162ba76

+ 1 - 1
CMakeLists.txt

@@ -7,8 +7,8 @@ project(ArduinoJson)
 
 enable_testing()
 
+add_definitions(-DARDUINOJSON_DEBUG)
 if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
-	add_definitions(-DARDUINOJSON_DEBUG)
 	add_compile_options(-g -O0)
 endif()
 

+ 2 - 0
scripts/code-size/arduino_avr_uno.csv

@@ -1,4 +1,6 @@
 Version,Date,JsonParserExample,JsonGeneratorExample
+v6.6.0-beta-6-g8217012,2018-11-27,7204,7630
+v6.6.0-beta-5-g13cc610,2018-11-27,7264,7850
 v6.6.0-beta-2-g2bd280d,2018-11-16,7872,8446
 v6.6.0-beta,2018-11-13,8380,8916
 v6.5.0-beta,2018-10-13,7384,7874

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

@@ -48,8 +48,6 @@ union JsonVariantContent {
   JsonArrayData asArray;
   JsonObjectData asObject;
   const char *asString;
-  struct StringSlot *asOwnedString;
-  struct StringSlot *asOwnedRaw;
   struct {
     const char *data;
     size_t size;

+ 2 - 2
src/ArduinoJson/Data/ObjectFunctions.hpp

@@ -103,9 +103,9 @@ inline bool objectCopy(JsonObjectData* dst, const JsonObjectData* src,
   for (VariantSlot* s = src->head; s; s = s->next) {
     JsonVariantData* var;
     if (s->value.keyIsOwned)
-      var = objectAdd(dst, ZeroTerminatedRamString(s->ownedKey->value), pool);
+      var = objectAdd(dst, ZeroTerminatedRamString(s->key), pool);
     else
-      var = objectAdd(dst, ZeroTerminatedRamStringConst(s->linkedKey), pool);
+      var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key), pool);
     if (!variantCopy(var, &s->value, pool)) return false;
   }
   return true;

+ 6 - 6
src/ArduinoJson/Data/SlotFunctions.hpp

@@ -13,28 +13,28 @@ namespace ARDUINOJSON_NAMESPACE {
 
 template <typename TKey>
 inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) {
-  StringSlot* slot = key.save(pool);
-  if (!slot) return false;
-  var->ownedKey = slot;
+  char* dup = key.save(pool);
+  if (!dup) return false;
+  var->key = dup;
   var->value.keyIsOwned = true;
   return true;
 }
 
 inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key,
                        MemoryPool*) {
-  var->linkedKey = key.c_str();
+  var->key = key.c_str();
   var->value.keyIsOwned = false;
   return true;
 }
 
 inline bool slotSetKey(VariantSlot* var, StringInMemoryPool key, MemoryPool*) {
-  var->ownedKey = key.slot();
+  var->key = key.c_str();
   var->value.keyIsOwned = true;
   return true;
 }
 
 inline const char* slotGetKey(const VariantSlot* var) {
-  return var->value.keyIsOwned ? var->ownedKey->value : var->linkedKey;
+  return var->key;
 }
 
 inline const VariantSlot* slotAdvance(const VariantSlot* var, size_t distance) {

+ 21 - 25
src/ArduinoJson/Data/VariantFunctions.hpp

@@ -22,9 +22,8 @@ inline T variantAsIntegral(const JsonVariantData* var) {
     case JSON_NEGATIVE_INTEGER:
       return T(~var->content.asInteger + 1);
     case JSON_LINKED_STRING:
-      return parseInteger<T>(var->content.asString);
     case JSON_OWNED_STRING:
-      return parseInteger<T>(var->content.asOwnedString->value);
+      return parseInteger<T>(var->content.asString);
     case JSON_FLOAT:
       return T(var->content.asFloat);
     default:
@@ -47,9 +46,8 @@ inline T variantAsFloat(const JsonVariantData* var) {
     case JSON_NEGATIVE_INTEGER:
       return -static_cast<T>(var->content.asInteger);
     case JSON_LINKED_STRING:
-      return parseFloat<T>(var->content.asString);
     case JSON_OWNED_STRING:
-      return parseFloat<T>(var->content.asOwnedString->value);
+      return parseFloat<T>(var->content.asString);
     case JSON_FLOAT:
       return static_cast<T>(var->content.asFloat);
     default:
@@ -61,9 +59,8 @@ inline const char* variantAsString(const JsonVariantData* var) {
   if (!var) return 0;
   switch (var->type) {
     case JSON_LINKED_STRING:
-      return var->content.asString;
     case JSON_OWNED_STRING:
-      return var->content.asOwnedString->value;
+      return var->content.asString;
     default:
       return 0;
   }
@@ -144,10 +141,11 @@ template <typename T>
 inline bool variantSetOwnedRaw(JsonVariantData* var, SerializedValue<T> value,
                                MemoryPool* pool) {
   if (!var) return false;
-  StringSlot* slot = makeString(value.data(), value.size()).save(pool);
-  if (slot) {
+  char* dup = makeString(value.data(), value.size()).save(pool);
+  if (dup) {
     var->type = JSON_OWNED_RAW;
-    var->content.asOwnedRaw = slot;
+    var->content.asRaw.data = dup;
+    var->content.asRaw.size = value.size();
     return true;
   } else {
     var->type = JSON_NULL;
@@ -158,10 +156,10 @@ inline bool variantSetOwnedRaw(JsonVariantData* var, SerializedValue<T> value,
 template <typename T>
 inline bool variantSetString(JsonVariantData* var, T value, MemoryPool* pool) {
   if (!var) return false;
-  StringSlot* slot = value.save(pool);
-  if (slot) {
+  char* dup = value.save(pool);
+  if (dup) {
     var->type = JSON_OWNED_STRING;
-    var->content.asOwnedString = slot;
+    var->content.asString = dup;
     return true;
   } else {
     var->type = JSON_NULL;
@@ -169,10 +167,10 @@ inline bool variantSetString(JsonVariantData* var, T value, MemoryPool* pool) {
   }
 }
 
-inline bool variantSetOwnedString(JsonVariantData* var, StringSlot* slot) {
+inline bool variantSetOwnedString(JsonVariantData* var, char* s) {
   if (!var) return false;
   var->type = JSON_OWNED_STRING;
-  var->content.asOwnedString = slot;
+  var->content.asString = s;
   return true;
 }
 
@@ -218,12 +216,11 @@ inline bool variantCopy(JsonVariantData* dst, const JsonVariantData* src,
       return objectCopy(variantToObject(dst), &src->content.asObject, pool);
     case JSON_OWNED_STRING:
       return variantSetString(
-          dst, makeString(src->content.asOwnedString->value), pool);
+          dst, ZeroTerminatedRamString(src->content.asString), pool);
     case JSON_OWNED_RAW:
-      return variantSetOwnedRaw(dst,
-                                serialized(src->content.asOwnedRaw->value,
-                                           src->content.asOwnedRaw->size),
-                                pool);
+      return variantSetOwnedRaw(
+          dst, serialized(src->content.asRaw.data, src->content.asRaw.size),
+          pool);
     default:
       // caution: don't override keyIsOwned
       dst->type = src->type;
@@ -266,16 +263,15 @@ inline bool variantEquals(const JsonVariantData* a, const JsonVariantData* b) {
   if (a->type != b->type) return false;
 
   switch (a->type) {
-    case JSON_LINKED_RAW:
     case JSON_LINKED_STRING:
+    case JSON_OWNED_STRING:
       return !strcmp(a->content.asString, b->content.asString);
 
+    case JSON_LINKED_RAW:
     case JSON_OWNED_RAW:
-    case JSON_OWNED_STRING:
-      return a->content.asOwnedString->size == b->content.asOwnedString->size &&
-             !memcmp(a->content.asOwnedString->value,
-                     b->content.asOwnedString->value,
-                     a->content.asOwnedString->size);
+      return a->content.asRaw.size == b->content.asRaw.size &&
+             !memcmp(a->content.asRaw.data, b->content.asRaw.data,
+                     a->content.asRaw.size);
 
     case JSON_BOOLEAN:
     case JSON_POSITIVE_INTEGER:

+ 1 - 1
src/ArduinoJson/JsonKey.hpp

@@ -19,7 +19,7 @@ class JsonKey {
   }
 
   bool isNull() const {
-    return _slot == 0 || _slot->linkedKey == 0;
+    return _slot == 0 || _slot->key == 0;
   }
 
   friend bool operator==(JsonKey lhs, const char* rhs) {

+ 2 - 1
src/ArduinoJson/JsonVariant.hpp

@@ -206,7 +206,8 @@ class JsonVariant : public JsonVariantProxy<JsonVariantData>,
 
   // for internal use only
   FORCE_INLINE bool set(StringInMemoryPool value) const {
-    return variantSetOwnedString(_data, value.slot());
+    return variantSetOwnedString(_data,
+                                 value.save(_memoryPool));  // TODO: remove?
   }
   FORCE_INLINE bool set(ZeroTerminatedRamStringConst value) const {
     return variantSetString(_data, value.c_str());

+ 1 - 6
src/ArduinoJson/JsonVariantImpl.hpp

@@ -89,15 +89,10 @@ inline void JsonVariantConst::accept(Visitor& visitor) const {
       return visitor.visitObject(JsonObjectConst(&_data->content.asObject));
 
     case JSON_LINKED_STRING:
-      return visitor.visitString(_data->content.asString);
-
     case JSON_OWNED_STRING:
-      return visitor.visitString(_data->content.asOwnedString->value);
+      return visitor.visitString(_data->content.asString);
 
     case JSON_OWNED_RAW:
-      return visitor.visitRawJson(_data->content.asOwnedRaw->value,
-                                  _data->content.asOwnedRaw->size);
-
     case JSON_LINKED_RAW:
       return visitor.visitRawJson(_data->content.asRaw.data,
                                   _data->content.asRaw.size);

+ 9 - 32
src/ArduinoJson/Memory/MemoryPool.hpp

@@ -23,21 +23,6 @@ namespace ARDUINOJSON_NAMESPACE {
 //             _left          _right
 
 class MemoryPool {
-  class UpdateStringSlotAddress {
-   public:
-    UpdateStringSlotAddress(const char* address, size_t offset)
-        : _address(address), _offset(offset) {}
-
-    void operator()(StringSlot* slot) const {
-      ARDUINOJSON_ASSERT(slot != NULL);
-      if (slot->value > _address) slot->value -= _offset;
-    }
-
-   private:
-    const char* _address;
-    size_t _offset;
-  };
-
  public:
   MemoryPool(char* buf, size_t capa)
       : _begin(buf),
@@ -66,34 +51,26 @@ class MemoryPool {
     return allocRight<VariantSlot>();
   }
 
-  StringSlot* allocFrozenString(size_t n) {
-    StringSlot* s = allocStringSlot();
-    if (!s) return 0;
+  char* allocFrozenString(size_t n) {
     if (!canAlloc(n)) return 0;
-
-    s->value = _left;
-    s->size = n;
+    char* s = _left;
     _left += n;
     checkInvariants();
-
     return s;
   }
 
-  StringSlot* allocExpandableString() {
-    StringSlot* s = allocStringSlot();
-    if (!s) return 0;
-
-    s->value = _left;
-    s->size = size_t(_right - _left);
+  StringSlot allocExpandableString() {
+    StringSlot s;
+    s.value = _left;
+    s.size = size_t(_right - _left);
     _left = _right;
-
     checkInvariants();
     return s;
   }
 
-  void freezeString(StringSlot* slot, size_t newSize) {
-    _left -= (slot->size - newSize);
-    slot->size = newSize;
+  void freezeString(StringSlot& s, size_t newSize) {
+    _left -= (s.size - newSize);
+    s.size = newSize;
     checkInvariants();
   }
 

+ 7 - 7
src/ArduinoJson/Memory/StringBuilder.hpp

@@ -26,28 +26,28 @@ class StringBuilder {
   }
 
   void append(char c) {
-    if (!_slot) return;
+    if (!_slot.value) return;
 
-    if (_size >= _slot->size) {
-      _slot = 0;
+    if (_size >= _slot.size) {
+      _slot.value = 0;
       return;
     }
 
-    _slot->value[_size++] = c;
+    _slot.value[_size++] = c;
   }
 
   StringType complete() {
     append('\0');
-    if (_slot) {
+    if (_slot.value) {
       _parent->freezeString(_slot, _size);
     }
-    return _slot;
+    return _slot.value;
   }
 
  private:
   MemoryPool* _parent;
   size_t _size;
-  StringSlot* _slot;
+  StringSlot _slot;
 };
 
 }  // namespace ARDUINOJSON_NAMESPACE

+ 1 - 3
src/ArduinoJson/Memory/StringSlot.hpp

@@ -7,14 +7,12 @@
 #include <stddef.h>  // for size_t
 #include "../Configuration.hpp"
 
-#define JSON_STRING_SIZE(SIZE) \
-  (sizeof(ARDUINOJSON_NAMESPACE::StringSlot) + (SIZE))
+#define JSON_STRING_SIZE(SIZE) (SIZE)
 
 namespace ARDUINOJSON_NAMESPACE {
 
 struct StringSlot {
   char *value;
   size_t size;
-  struct StringSlot *next;
 };
 }  // namespace ARDUINOJSON_NAMESPACE

+ 1 - 4
src/ArduinoJson/Memory/VariantSlot.hpp

@@ -12,10 +12,7 @@ struct VariantSlot {
   JsonVariantData value;
   struct VariantSlot* next;
   struct VariantSlot* prev;
-  union {
-    const char* linkedKey;
-    StringSlot* ownedKey;
-  };
+  const char* key;
 };
 
 }  // namespace ARDUINOJSON_NAMESPACE

+ 4 - 5
src/ArduinoJson/Strings/ArduinoString.hpp

@@ -12,13 +12,12 @@ class ArduinoString {
  public:
   ArduinoString(const ::String& str) : _str(&str) {}
 
-  template <typename TMemoryPool>
-  StringSlot* save(TMemoryPool* memoryPool) const {
+  char* save(MemoryPool* memoryPool) const {
     if (isNull()) return NULL;
     size_t n = _str->length() + 1;
-    StringSlot* slot = memoryPool->allocFrozenString(n);
-    if (slot) memcpy(slot->value, _str->c_str(), n);
-    return slot;
+    char* dup = memoryPool->allocFrozenString(n);
+    if (dup) memcpy(dup, _str->c_str(), n);
+    return dup;
   }
 
   bool isNull() const {

+ 4 - 5
src/ArduinoJson/Strings/FixedSizeFlashString.hpp

@@ -21,12 +21,11 @@ class FixedSizeFlashString {
     return !_str;
   }
 
-  template <typename TMemoryPool>
-  StringSlot* save(TMemoryPool* memoryPool) const {
+  char* save(MemoryPool* memoryPool) const {
     if (!_str) return NULL;
-    StringSlot* slot = memoryPool->allocFrozenString(_size);
-    if (!slot) memcpy_P(slot->value, (const char*)_str, _size);
-    return slot;
+    char* dup = memoryPool->allocFrozenString(_size);
+    if (!dup) memcpy_P(dup, (const char*)_str, _size);
+    return dup;
   }
 
   size_t size() const {

+ 4 - 4
src/ArduinoJson/Strings/FixedSizeRamString.hpp

@@ -23,11 +23,11 @@ class FixedSizeRamString {
   }
 
   template <typename TMemoryPool>
-  StringSlot* save(TMemoryPool* memoryPool) const {
+  char* save(TMemoryPool* memoryPool) const {
     if (!_str) return NULL;
-    StringSlot* slot = memoryPool->allocFrozenString(_size);
-    if (slot) memcpy(slot->value, _str, _size);
-    return slot;
+    char* dup = memoryPool->allocFrozenString(_size);
+    if (dup) memcpy(dup, _str, _size);
+    return dup;
   }
 
   size_t size() const {

+ 4 - 5
src/ArduinoJson/Strings/StlString.hpp

@@ -12,12 +12,11 @@ class StlString {
  public:
   StlString(const std::string& str) : _str(&str) {}
 
-  template <typename TMemoryPool>
-  StringSlot* save(TMemoryPool* memoryPool) const {
+  char* save(MemoryPool* memoryPool) const {
     size_t n = _str->length() + 1;
-    StringSlot* slot = memoryPool->allocFrozenString(n);
-    if (slot) memcpy(slot->value, _str->c_str(), n);
-    return slot;
+    char* dup = memoryPool->allocFrozenString(n);
+    if (dup) memcpy(dup, _str->c_str(), n);
+    return dup;
   }
 
   bool isNull() const {

+ 10 - 19
src/ArduinoJson/Strings/StringInMemoryPool.hpp

@@ -5,44 +5,35 @@
 #pragma once
 
 #include <string.h>
-#include "../Memory/StringSlot.hpp"
+#include "../Memory/MemoryPool.hpp"
 
 namespace ARDUINOJSON_NAMESPACE {
 
 class StringInMemoryPool {
  public:
-  StringInMemoryPool(StringSlot* s = 0) : _slot(s) {}
+  StringInMemoryPool(char* s = 0) : _value(s) {}
 
   bool equals(const char* expected) const {
-    if (!_slot) return expected == 0;
-    const char* actual = _slot->value;
+    if (!_value) return expected == 0;
+    const char* actual = _value;
     if (actual == expected) return true;
     return strcmp(actual, expected) == 0;
   }
 
-  bool isNull() const {
-    return !_slot;
-  }
-
-  template <typename TMemoryPool>
-  StringSlot* save(TMemoryPool*) const {
-    return _slot;
+  char* save(void*) {
+    return _value;
   }
 
-  size_t size() const {
-    return _slot->size;
-  }
-
-  StringSlot* slot() const {
-    return _slot;
+  bool isNull() const {
+    return !_value;
   }
 
   const char* c_str() const {
-    return _slot->value;
+    return _value;
   }
 
  protected:
-  StringSlot* _slot;
+  char* _value;
 };
 
 }  // namespace ARDUINOJSON_NAMESPACE

+ 4 - 5
src/ArduinoJson/Strings/ZeroTerminatedFlashString.hpp

@@ -20,13 +20,12 @@ class ZeroTerminatedFlashString {
     return !_str;
   }
 
-  template <typename TMemoryPool>
-  StringSlot* save(TMemoryPool* memoryPool) const {
+  char* save(MemoryPool* memoryPool) const {
     if (!_str) return NULL;
     size_t n = size() + 1;  // copy the terminator
-    StringSlot* slot = memoryPool->allocFrozenString(n);
-    if (slot) memcpy_P(slot->value, reinterpret_cast<const char*>(_str), n);
-    return slot;
+    char* dup = memoryPool->allocFrozenString(n);
+    if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
+    return dup;
   }
 
   size_t size() const {

+ 4 - 4
src/ArduinoJson/Strings/ZeroTerminatedRamString.hpp

@@ -14,12 +14,12 @@ class ZeroTerminatedRamString : public ZeroTerminatedRamStringConst {
       : ZeroTerminatedRamStringConst(str) {}
 
   template <typename TMemoryPool>
-  StringSlot* save(TMemoryPool* memoryPool) const {
+  char* save(TMemoryPool* memoryPool) const {
     if (!_str) return NULL;
     size_t n = size() + 1;
-    StringSlot* slot = memoryPool->allocFrozenString(n);
-    if (slot) memcpy(slot->value, _str, n);
-    return slot;
+    char* dup = memoryPool->allocFrozenString(n);
+    if (dup) memcpy(dup, _str, n);
+    return dup;
   }
 };
 

+ 2 - 2
test/JsonVariant/set.cpp

@@ -79,12 +79,12 @@ TEST_CASE("JsonVariant with not enough memory") {
   JsonVariant v = doc.to<JsonVariant>();
 
   SECTION("std::string") {
-    v.set(std::string("hello"));
+    v.set(std::string("hello world!!"));
     REQUIRE(v.isNull());
   }
 
   SECTION("Serialized<std::string>") {
-    v.set(serialized(std::string("hello")));
+    v.set(serialized(std::string("hello world!!")));
     REQUIRE(v.isNull());
   }
 }

+ 12 - 22
test/MemoryPool/allocString.cpp

@@ -9,26 +9,22 @@ using namespace ARDUINOJSON_NAMESPACE;
 
 TEST_CASE("MemoryPool::allocFrozenString()") {
   const size_t poolCapacity = 64;
-  const size_t longestString = poolCapacity - sizeof(StringSlot);
+  const size_t longestString = poolCapacity;
   char buffer[poolCapacity];
   MemoryPool pool(buffer, poolCapacity);
 
   SECTION("Returns different addresses") {
-    StringSlot *a = pool.allocFrozenString(1);
-    StringSlot *b = pool.allocFrozenString(1);
+    char *a = pool.allocFrozenString(1);
+    char *b = pool.allocFrozenString(1);
     REQUIRE(a != b);
-    REQUIRE(a->value != b->value);
-  }
-
-  SECTION("Returns a StringSlot of the right size") {
-    StringSlot *s = pool.allocFrozenString(12);
-    REQUIRE(s->size == 12);
   }
 
   SECTION("Returns NULL when full") {
-    pool.allocFrozenString(longestString);
-    void *p = pool.allocFrozenString(1);
-    REQUIRE(0 == p);
+    void *p1 = pool.allocFrozenString(longestString);
+    REQUIRE(p1 != 0);
+
+    void *p2 = pool.allocFrozenString(1);
+    REQUIRE(p2 == 0);
   }
 
   SECTION("Returns NULL when pool is too small") {
@@ -46,22 +42,16 @@ TEST_CASE("MemoryPool::allocFrozenString()") {
     REQUIRE(0 == pool2.allocFrozenString(2));
   }
 
-  SECTION("Returns aligned pointers") {
-    REQUIRE(isAligned(pool.allocFrozenString(1)));
-    REQUIRE(isAligned(pool.allocFrozenString(1)));
-  }
-
   SECTION("Returns same address after clear()") {
-    StringSlot *a = pool.allocFrozenString(1);
+    void *a = pool.allocFrozenString(1);
     pool.clear();
-    StringSlot *b = pool.allocFrozenString(1);
+    void *b = pool.allocFrozenString(1);
 
     REQUIRE(a == b);
-    REQUIRE(a->value == b->value);
   }
 
   SECTION("Can use full capacity when fresh") {
-    StringSlot *a = pool.allocFrozenString(longestString);
+    void *a = pool.allocFrozenString(longestString);
 
     REQUIRE(a != 0);
   }
@@ -70,7 +60,7 @@ TEST_CASE("MemoryPool::allocFrozenString()") {
     pool.allocFrozenString(longestString);
     pool.clear();
 
-    StringSlot *a = pool.allocFrozenString(longestString);
+    void *a = pool.allocFrozenString(longestString);
 
     REQUIRE(a != 0);
   }

+ 2 - 2
test/MemoryPool/size.cpp

@@ -28,11 +28,11 @@ TEST_CASE("MemoryPool::size()") {
   }
 
   SECTION("Decreases after freezeString()") {
-    StringSlot* a = memoryPool.allocExpandableString();
+    StringSlot a = memoryPool.allocExpandableString();
     memoryPool.freezeString(a, 1);
     REQUIRE(memoryPool.size() == JSON_STRING_SIZE(1));
 
-    StringSlot* b = memoryPool.allocExpandableString();
+    StringSlot b = memoryPool.allocExpandableString();
     memoryPool.freezeString(b, 1);
     REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(1));
   }