BasicJsonDocument.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2022, Benoit BLANCHON
  3. // MIT License
  4. #pragma once
  5. #include <ArduinoJson/Document/JsonDocument.hpp>
  6. namespace ARDUINOJSON_NAMESPACE {
  7. // Helper to implement the "base-from-member" idiom
  8. // (we need to store the allocator before constructing JsonDocument)
  9. template <typename TAllocator>
  10. class AllocatorOwner {
  11. public:
  12. AllocatorOwner() {}
  13. AllocatorOwner(TAllocator a) : _allocator(a) {}
  14. void* allocate(size_t size) {
  15. return _allocator.allocate(size);
  16. }
  17. void deallocate(void* ptr) {
  18. if (ptr)
  19. _allocator.deallocate(ptr);
  20. }
  21. void* reallocate(void* ptr, size_t new_size) {
  22. return _allocator.reallocate(ptr, new_size);
  23. }
  24. TAllocator& allocator() {
  25. return _allocator;
  26. }
  27. private:
  28. TAllocator _allocator;
  29. };
  30. template <typename TAllocator>
  31. class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
  32. public:
  33. explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator())
  34. : AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) {}
  35. // Copy-constructor
  36. BasicJsonDocument(const BasicJsonDocument& src)
  37. : AllocatorOwner<TAllocator>(src), JsonDocument() {
  38. copyAssignFrom(src);
  39. }
  40. // Move-constructor
  41. #if ARDUINOJSON_HAS_RVALUE_REFERENCES
  42. BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) {
  43. moveAssignFrom(src);
  44. }
  45. #endif
  46. BasicJsonDocument(const JsonDocument& src) {
  47. copyAssignFrom(src);
  48. }
  49. // Construct from variant, array, or object
  50. template <typename T>
  51. BasicJsonDocument(
  52. const T& src,
  53. typename enable_if<
  54. is_same<T, VariantRef>::value ||
  55. is_same<T, JsonVariantConst>::value || is_same<T, JsonArray>::value ||
  56. is_same<T, JsonArrayConst>::value || is_same<T, JsonObject>::value ||
  57. is_same<T, JsonObjectConst>::value>::type* = 0)
  58. : JsonDocument(allocPool(src.memoryUsage())) {
  59. set(src);
  60. }
  61. // disambiguate
  62. BasicJsonDocument(VariantRef src)
  63. : JsonDocument(allocPool(src.memoryUsage())) {
  64. set(src);
  65. }
  66. ~BasicJsonDocument() {
  67. freePool();
  68. }
  69. BasicJsonDocument& operator=(const BasicJsonDocument& src) {
  70. copyAssignFrom(src);
  71. return *this;
  72. }
  73. #if ARDUINOJSON_HAS_RVALUE_REFERENCES
  74. BasicJsonDocument& operator=(BasicJsonDocument&& src) {
  75. moveAssignFrom(src);
  76. return *this;
  77. }
  78. #endif
  79. template <typename T>
  80. BasicJsonDocument& operator=(const T& src) {
  81. size_t requiredSize = src.memoryUsage();
  82. if (requiredSize > capacity())
  83. reallocPool(requiredSize);
  84. set(src);
  85. return *this;
  86. }
  87. void shrinkToFit() {
  88. ptrdiff_t bytes_reclaimed = _pool.squash();
  89. if (bytes_reclaimed == 0)
  90. return;
  91. void* old_ptr = _pool.buffer();
  92. void* new_ptr = this->reallocate(old_ptr, _pool.capacity());
  93. ptrdiff_t ptr_offset =
  94. static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
  95. _pool.movePointers(ptr_offset);
  96. _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
  97. }
  98. bool garbageCollect() {
  99. // make a temporary clone and move assign
  100. BasicJsonDocument tmp(*this);
  101. if (!tmp.capacity())
  102. return false;
  103. tmp.set(*this);
  104. moveAssignFrom(tmp);
  105. return true;
  106. }
  107. using AllocatorOwner<TAllocator>::allocator;
  108. private:
  109. MemoryPool allocPool(size_t requiredSize) {
  110. size_t capa = addPadding(requiredSize);
  111. return MemoryPool(reinterpret_cast<char*>(this->allocate(capa)), capa);
  112. }
  113. void reallocPool(size_t requiredSize) {
  114. size_t capa = addPadding(requiredSize);
  115. if (capa == _pool.capacity())
  116. return;
  117. freePool();
  118. replacePool(allocPool(addPadding(requiredSize)));
  119. }
  120. void freePool() {
  121. this->deallocate(getPool()->buffer());
  122. }
  123. void copyAssignFrom(const JsonDocument& src) {
  124. reallocPool(src.capacity());
  125. set(src);
  126. }
  127. void moveAssignFrom(BasicJsonDocument& src) {
  128. freePool();
  129. _data = src._data;
  130. _pool = src._pool;
  131. src._data.setNull();
  132. src._pool = MemoryPool(0, 0);
  133. }
  134. };
  135. } // namespace ARDUINOJSON_NAMESPACE