Minh Nguyen / ArduinoJson
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BasicJsonDocument.hpp Source File

BasicJsonDocument.hpp

00001 // ArduinoJson - arduinojson.org
00002 // Copyright Benoit Blanchon 2014-2021
00003 // MIT License
00004 
00005 #pragma once
00006 
00007 #include <ArduinoJson/Document/JsonDocument.hpp>
00008 
00009 namespace ARDUINOJSON_NAMESPACE {
00010 
00011 // Helper to implement the "base-from-member" idiom
00012 // (we need to store the allocator before constructing JsonDocument)
00013 template <typename TAllocator>
00014 class AllocatorOwner {
00015  public:
00016   AllocatorOwner() {}
00017   AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {}
00018   AllocatorOwner(TAllocator a) : _allocator(a) {}
00019 
00020   void* allocate(size_t size) {
00021     return _allocator.allocate(size);
00022   }
00023 
00024   void deallocate(void* ptr) {
00025     if (ptr)
00026       _allocator.deallocate(ptr);
00027   }
00028 
00029   void* reallocate(void* ptr, size_t new_size) {
00030     return _allocator.reallocate(ptr, new_size);
00031   }
00032 
00033   TAllocator& allocator() {
00034     return _allocator;
00035   }
00036 
00037  private:
00038   TAllocator _allocator;
00039 };
00040 
00041 template <typename TAllocator>
00042 class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
00043  public:
00044   explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator())
00045       : AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) {}
00046 
00047   // Copy-constructor
00048   BasicJsonDocument(const BasicJsonDocument& src)
00049       : AllocatorOwner<TAllocator>(src), JsonDocument() {
00050     copyAssignFrom(src);
00051   }
00052 
00053   // Move-constructor
00054 #if ARDUINOJSON_HAS_RVALUE_REFERENCES
00055   BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) {
00056     moveAssignFrom(src);
00057   }
00058 #endif
00059 
00060   BasicJsonDocument(const JsonDocument& src) {
00061     copyAssignFrom(src);
00062   }
00063 
00064   // Construct from variant, array, or object
00065   template <typename T>
00066   BasicJsonDocument(
00067       const T& src,
00068       typename enable_if<
00069           is_same<T, VariantRef>::value || is_same<T, VariantConstRef>::value ||
00070           is_same<T, ArrayRef>::value || is_same<T, ArrayConstRef>::value ||
00071           is_same<T, ObjectRef>::value ||
00072           is_same<T, ObjectConstRef>::value>::type* = 0)
00073       : JsonDocument(allocPool(src.memoryUsage())) {
00074     set(src);
00075   }
00076 
00077   // disambiguate
00078   BasicJsonDocument(VariantRef src)
00079       : JsonDocument(allocPool(src.memoryUsage())) {
00080     set(src);
00081   }
00082 
00083   ~BasicJsonDocument() {
00084     freePool();
00085   }
00086 
00087   BasicJsonDocument& operator=(const BasicJsonDocument& src) {
00088     copyAssignFrom(src);
00089     return *this;
00090   }
00091 
00092 #if ARDUINOJSON_HAS_RVALUE_REFERENCES
00093   BasicJsonDocument& operator=(BasicJsonDocument&& src) {
00094     moveAssignFrom(src);
00095     return *this;
00096   }
00097 #endif
00098 
00099   template <typename T>
00100   BasicJsonDocument& operator=(const T& src) {
00101     reallocPoolIfTooSmall(src.memoryUsage());
00102     set(src);
00103     return *this;
00104   }
00105 
00106   void shrinkToFit() {
00107     ptrdiff_t bytes_reclaimed = _pool.squash();
00108     if (bytes_reclaimed == 0)
00109       return;
00110 
00111     void* old_ptr = _pool.buffer();
00112     void* new_ptr = this->reallocate(old_ptr, _pool.capacity());
00113 
00114     ptrdiff_t ptr_offset =
00115         static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
00116 
00117     _pool.movePointers(ptr_offset);
00118     _data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
00119   }
00120 
00121   bool garbageCollect() {
00122     // make a temporary clone and move assign
00123     BasicJsonDocument tmp(*this);
00124     if (!tmp.capacity())
00125       return false;
00126     tmp.set(*this);
00127     moveAssignFrom(tmp);
00128     return true;
00129   }
00130 
00131   using AllocatorOwner<TAllocator>::allocator;
00132 
00133  private:
00134   MemoryPool allocPool(size_t requiredSize) {
00135     size_t capa = addPadding(requiredSize);
00136     return MemoryPool(reinterpret_cast<char*>(this->allocate(capa)), capa);
00137   }
00138 
00139   void reallocPoolIfTooSmall(size_t requiredSize) {
00140     if (requiredSize <= capacity())
00141       return;
00142     freePool();
00143     replacePool(allocPool(addPadding(requiredSize)));
00144   }
00145 
00146   void freePool() {
00147     this->deallocate(memoryPool().buffer());
00148   }
00149 
00150   void copyAssignFrom(const JsonDocument& src) {
00151     reallocPoolIfTooSmall(src.capacity());
00152     set(src);
00153   }
00154 
00155   void moveAssignFrom(BasicJsonDocument& src) {
00156     freePool();
00157     _data = src._data;
00158     _pool = src._pool;
00159     src._data.setNull();
00160     src._pool = MemoryPool(0, 0);
00161   }
00162 };
00163 
00164 }  // namespace ARDUINOJSON_NAMESPACE