Minh Nguyen / ArduinoJson
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MemoryPool.hpp Source File

MemoryPool.hpp

00001 // ArduinoJson - arduinojson.org
00002 // Copyright Benoit Blanchon 2014-2021
00003 // MIT License
00004 
00005 #pragma once
00006 
00007 #include <ArduinoJson/Memory/Alignment.hpp>
00008 #include <ArduinoJson/Polyfills/assert.hpp>
00009 #include <ArduinoJson/Polyfills/mpl/max.hpp>
00010 #include <ArduinoJson/Variant/VariantSlot.hpp>
00011 
00012 #include <string.h>  // memmove
00013 
00014 #define JSON_STRING_SIZE(SIZE) (SIZE + 1)
00015 
00016 namespace ARDUINOJSON_NAMESPACE {
00017 
00018 // _begin                                   _end
00019 // v                                           v
00020 // +-------------+--------------+--------------+
00021 // | strings...  |   (free)     |  ...variants |
00022 // +-------------+--------------+--------------+
00023 //               ^              ^
00024 //             _left          _right
00025 
00026 class MemoryPool {
00027  public:
00028   MemoryPool(char* buf, size_t capa)
00029       : _begin(buf),
00030         _left(buf),
00031         _right(buf ? buf + capa : 0),
00032         _end(buf ? buf + capa : 0),
00033         _overflowed(false) {
00034     ARDUINOJSON_ASSERT(isAligned(_begin));
00035     ARDUINOJSON_ASSERT(isAligned(_right));
00036     ARDUINOJSON_ASSERT(isAligned(_end));
00037   }
00038 
00039   void* buffer() {
00040     return _begin;
00041   }
00042 
00043   // Gets the capacity of the memoryPool in bytes
00044   size_t capacity() const {
00045     return size_t(_end - _begin);
00046   }
00047 
00048   size_t size() const {
00049     return size_t(_left - _begin + _end - _right);
00050   }
00051 
00052   bool overflowed() const {
00053     return _overflowed;
00054   }
00055 
00056   VariantSlot* allocVariant() {
00057     return allocRight<VariantSlot>();
00058   }
00059 
00060   template <typename TAdaptedString>
00061   const char* saveString(const TAdaptedString& str) {
00062     if (str.isNull())
00063       return 0;
00064 
00065 #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
00066     const char* existingCopy = findString(str.begin());
00067     if (existingCopy)
00068       return existingCopy;
00069 #endif
00070 
00071     size_t n = str.size();
00072 
00073     char* newCopy = allocString(n + 1);
00074     if (newCopy) {
00075       str.copyTo(newCopy, n);
00076       newCopy[n] = 0;  // force null-terminator
00077     }
00078     return newCopy;
00079   }
00080 
00081   void getFreeZone(char** zoneStart, size_t* zoneSize) const {
00082     *zoneStart = _left;
00083     *zoneSize = size_t(_right - _left);
00084   }
00085 
00086   const char* saveStringFromFreeZone(size_t len) {
00087 #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
00088     const char* dup = findString(_left);
00089     if (dup)
00090       return dup;
00091 #endif
00092 
00093     const char* str = _left;
00094     _left += len;
00095     checkInvariants();
00096     return str;
00097   }
00098 
00099   void markAsOverflowed() {
00100     _overflowed = true;
00101   }
00102 
00103   void clear() {
00104     _left = _begin;
00105     _right = _end;
00106     _overflowed = false;
00107   }
00108 
00109   bool canAlloc(size_t bytes) const {
00110     return _left + bytes <= _right;
00111   }
00112 
00113   bool owns(void* p) const {
00114     return _begin <= p && p < _end;
00115   }
00116 
00117   // Workaround for missing placement new
00118   void* operator new(size_t, void* p) {
00119     return p;
00120   }
00121 
00122   // Squash the free space between strings and variants
00123   //
00124   // _begin                    _end
00125   // v                            v
00126   // +-------------+--------------+
00127   // | strings...  |  ...variants |
00128   // +-------------+--------------+
00129   //               ^
00130   //          _left _right
00131   //
00132   // This funcion is called before a realloc.
00133   ptrdiff_t squash() {
00134     char* new_right = addPadding(_left);
00135     if (new_right >= _right)
00136       return 0;
00137 
00138     size_t right_size = static_cast<size_t>(_end - _right);
00139     memmove(new_right, _right, right_size);
00140 
00141     ptrdiff_t bytes_reclaimed = _right - new_right;
00142     _right = new_right;
00143     _end = new_right + right_size;
00144     return bytes_reclaimed;
00145   }
00146 
00147   // Move all pointers together
00148   // This funcion is called after a realloc.
00149   void movePointers(ptrdiff_t offset) {
00150     _begin += offset;
00151     _left += offset;
00152     _right += offset;
00153     _end += offset;
00154   }
00155 
00156  private:
00157   void checkInvariants() {
00158     ARDUINOJSON_ASSERT(_begin <= _left);
00159     ARDUINOJSON_ASSERT(_left <= _right);
00160     ARDUINOJSON_ASSERT(_right <= _end);
00161     ARDUINOJSON_ASSERT(isAligned(_right));
00162   }
00163 
00164 #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
00165   template <typename TIterator>
00166   const char* findString(TIterator str) {
00167     for (char* next = _begin; next < _left; ++next) {
00168       char* begin = next;
00169 
00170       // try to match
00171       for (TIterator it = str; *it == *next; ++it) {
00172         if (*next++ == 0)
00173           return begin;
00174       }
00175 
00176       // jump to next terminator
00177       while (*next) ++next;
00178     }
00179     return 0;
00180   }
00181 #endif
00182 
00183   char* allocString(size_t n) {
00184     if (!canAlloc(n)) {
00185       _overflowed = true;
00186       return 0;
00187     }
00188     char* s = _left;
00189     _left += n;
00190     checkInvariants();
00191     return s;
00192   }
00193 
00194   template <typename T>
00195   T* allocRight() {
00196     return reinterpret_cast<T*>(allocRight(sizeof(T)));
00197   }
00198 
00199   void* allocRight(size_t bytes) {
00200     if (!canAlloc(bytes)) {
00201       _overflowed = true;
00202       return 0;
00203     }
00204     _right -= bytes;
00205     return _right;
00206   }
00207 
00208   char *_begin, *_left, *_right, *_end;
00209   bool _overflowed;
00210 };
00211 
00212 }  // namespace ARDUINOJSON_NAMESPACE